update dashboard components

- Layout now utilizes framer-motion to be more adaptive
- Section bow allows for an icon and optional separator
- Sidebar is now restructured and its child components are exported (Item, Header, Separator)
pull/67/head
dperolio 3 years ago
parent 556ea7e260
commit e205fcb306
No known key found for this signature in database
GPG Key ID: 3E9BBAA710D3DDCE

@ -1,32 +1,35 @@
/**
*
* @component
*/
import { AdvancedScrollerAuto, ErrorBoundary } from '@vizality/components';
import { joinClassNames } from '@vizality/util/dom';
import { getModule } from '@vizality/webpack';
import React, { memo } from 'react';
import { AnimateSharedLayout, AnimatePresence, motion } from 'framer-motion';
/**
*
* @component
*/
export default memo(({ className, wrapperClassName, children }) => {
const { pageWrapper } = getModule('pageWrapper');
const { scroller } = getModule('headerContentWrapper');
const { pageWrapper } = getModule('pageWrapper');
const { perksModal } = getModule('perksModal');
const { base } = getModule('base');
const { content } = getModule('wrappedLayout');
const { base } = getModule('base');
return (
<div className={joinClassNames('vz-dashboard', wrapperClassName, pageWrapper, perksModal)}>
<AdvancedScrollerAuto className={`${scroller} vz-dashboard-scroller`}>
<div className={joinClassNames('vz-dashboard-layout', className)}>
<ErrorBoundary
className='vz-dashboard-error-boundary'
headerClassName={joinClassNames('vz-dashboard-content-header', base, content)}
showScene={true}
>
{children}
</ErrorBoundary>
</div>
</AdvancedScrollerAuto>
</div>
<AnimateSharedLayout>
<AnimatePresence>
<motion.div layout layoutId='dashboard' className={joinClassNames('vz-dashboard', wrapperClassName, pageWrapper, perksModal)}>
<AdvancedScrollerAuto className={`${scroller} vz-dashboard-scroller`}>
<div className={joinClassNames('vz-dashboard-layout', className)}>
<ErrorBoundary
className='vz-dashboard-error-boundary'
headerClassName={joinClassNames('vz-dashboard-content-header', base, content)}
showScene={true}
>
{children}
</ErrorBoundary>
</div>
</AdvancedScrollerAuto>
</motion.div>
</AnimatePresence>
</AnimateSharedLayout>
);
});

@ -1,37 +1,62 @@
/**
*
* @component
*/
import { joinClassNames } from '@vizality/util/dom';
import { Divider, Icon } from '@vizality/components';
import { getModule } from '@vizality/webpack';
import { motion } from 'framer-motion';
import React, { memo } from 'react';
const Header = memo(({ heading, subheading }) => {
/**
* Dashboard section header.
* @component
* @param {string|React.Component|function(): React.ReactElement} [header] Section header
* @param {string|React.Component|function(): React.ReactElement} [description] Section description
* @returns {React.MemoExoticComponent<function(): React.ReactElement>}
*/
export const Header = memo(({ icon, header, description, separator }) => {
const { marginBottom40 } = getModule('marginBottom20');
const { headerSubtext } = getModule('headerSubtext');
const { content } = getModule('wrappedLayout');
const { h1 } = getModule('h1', 'h2', 'h3');
const { size32 } = getModule('size24');
const { size24 } = getModule('size24');
const { base } = getModule('base');
return (
<div className={joinClassNames('vz-dashboard-section-header-wrapper', marginBottom40)}>
<h2 className={joinClassNames('vz-dashboard-section-header', size32, base, content)}>
{heading}
</h2>
<h4 className={joinClassNames('vz-dashboard-section-header-subtext', h1, headerSubtext)}>
{subheading}
<motion.div layout='position' className={joinClassNames('vz-dashboard-section-header-wrapper', marginBottom40)}>
<div className='vz-dashboard-content-header-inner-wrapper'>
{icon && (
<Icon
className='vz-dashboard-section-header-icon-wrapper'
iconClassName='vz-dashboard-section-header-icon'
name={icon}
size='100%'
/>
)}
<h2 className={joinClassNames('vz-dashboard-section-header', size24, base, content)}>
{header}
</h2>
</div>
<h4 className={joinClassNames('vz-dashboard-section-header-description', h1, headerSubtext)}>
{description}
</h4>
</div>
{separator && (
<Divider />
)}
</motion.div>
);
});
export default memo(({ heading, subheading, className, children }) => {
/**
* Dashboard content section.
* @component
* @param {string|React.Component|function(): React.ReactElement} [header] Section header
* @param {string|React.Component|function(): React.ReactElement} [description] Section description
* @param {string} [className] Section class
* @param {...any} [children] Section children
* @returns {React.MemoExoticComponent<function(): React.ReactElement>}
*/
export default memo(({ header, description, icon, separator = true, className, children }) => {
return (
<div className={joinClassNames('vz-dashboard-section', className)}>
{heading && (
<Header heading={heading} subheading={subheading} />
{header && (
<Header header={header} description={description} icon={icon} separator={separator} />
)}
<div className='vz-dashboard-section-contents'>
{children}

@ -1,14 +1,123 @@
import { AdvancedScrollerThin, ErrorBoundary, Icon, ContextMenu, Clickable, DiscoverySidebarHeader } from '@vizality/components';
import { getModule, contextMenu } from '@vizality/webpack';
import { joinClassNames } from '@vizality/util/dom';
import React, { memo } from 'react';
const { openContextMenu, closeContextMenu } = contextMenu;
/**
* Dashboard sidebar.
* Dashboard sidebar header.
* @component
* @returns {React.MemoExoticComponent<function(): React.ReactElement>}
*/
export const Header = memo(({ text, children, className }) => {
return (
<div className={joinClassNames('vz-dashboard-sidebar-header', className)}>
<DiscoverySidebarHeader text={text} />
{children}
</div>
);
});
import { AdvancedScrollerThin, ErrorBoundary, Icon } from '@vizality/components';
import { joinClassNames } from '@vizality/util/dom';
import React, { memo } from 'react';
/**
* Dashboard sidebar navigation item separator.
* @component
* @returns {React.MemoExoticComponent<function(): React.ReactElement>}
*/
export const Separator = memo(({ className }) => (
<div className={joinClassNames('vz-dashboard-sidebar-separator', className)} />
));
import { SidebarHeader, SidebarItem, SidebarSeparator } from '.';
/**
* Context menu for dashboard sidebar navigation items.
* @private
* @component
* @returns {React.MemoExoticComponent<function(): React.ReactElement>}
*/
const ItemContextMenu = memo(({ path }) => {
return (
<ContextMenu.Menu navId='dashboard-item' onClose={closeContextMenu}>
<ContextMenu.Item
id='copy-link'
label='Copy Link'
action={() => DiscordNative?.clipboard?.copy(`<vizality:/${path.replace('vizality/', '')}>`)}
/>
</ContextMenu.Menu>
);
});
/**
* Dashboard sidebar navigation item.
* @component
* @returns {React.MemoExoticComponent<function(): React.ReactElement>}
*/
export const Item = memo(({ icon, children, route, selected, disabled, onContextMenu, tooltip, tooltipPosition, onClick, className }) => {
selected = typeof selected === 'boolean' ? selected : vizality.api.routes.getLocation()?.pathname?.startsWith(route);
const { categoryItem, selectedCategoryItem, itemInner } = getModule('categoryItem', 'selectedCategoryItem', 'itemInner');
const { container, selected: selectedClass, wrappedLayout, layout, avatar, content, nameAndDecorators, name, wrappedName, clickable } = getModule('wrappedLayout', 'wrappedName', 'layout');
return (
<Clickable
onContextMenu={evt => {
try {
if (disabled) {
return;
}
if (onContextMenu) {
return onContextMenu();
} else if (route) {
return openContextMenu(evt, () => <ItemContextMenu path={route} />);
}
} catch (err) {
}
}}
onClick={() => {
try {
if (disabled) {
return;
}
if (onClick) {
return onClick();
} else if (route) {
return vizality.api.routes.navigateTo(route);
}
} catch (err) {
}
}}
vz-selected={selected && ''}
vz-disabled={disabled && ''}
className={joinClassNames('vz-dashboard-sidebar-item', className, categoryItem, container, {
disabled,
[`${selectedClass} ${selectedCategoryItem}`]: selected,
[clickable]: !selected
})}
>
<div className={joinClassNames('vz-dashboard-sidebar-item-inner', itemInner, layout, wrappedLayout)}>
<Icon
className={joinClassNames('vz-dashboard-sidebar-item-icon-wrapper', avatar)}
iconClassName='vz-dashboard-sidebar-item-icon'
name={icon}
tooltip={tooltip}
tooltipPosition={tooltipPosition || 'right'}
/>
<div className={content}>
<div className={nameAndDecorators}>
<div className={joinClassNames(name, wrappedName)}>
{children}
</div>
</div>
</div>
</div>
</Clickable>
);
});
/**
* Dashboard sidebar.
* @component
* @returns {React.MemoExoticComponent<function(): React.ReactElement>}
*/
export default memo(({ header, className, children }) => {
const [ collapsed, setCollapsed ] = vizality.api.settings.useSetting('dashboardSidebarCollapse', false);
@ -20,7 +129,7 @@ export default memo(({ header, className, children }) => {
* If no header prop is provided, render the default Vizality dashboard sidebar header.
*/
? (
<SidebarHeader text='Dashboard'>
<Header text='Dashboard'>
<Icon
name='Download'
iconClassName='vz-dashboard-sidebar-collapser-icon'
@ -29,13 +138,13 @@ export default memo(({ header, className, children }) => {
tooltip={collapsed ? 'Expand' : 'Collapse'}
tooltipPosition='right'
/>
</SidebarHeader>
</Header>
)
/**
* If header prop provided is a string, use that.
*/
: typeof header === 'string'
? <SidebarHeader text={header} />
? <Header text={header} />
/**
* If header prop is provided but isn't a string, we'll assume it's a React component
* and render that.
@ -46,25 +155,38 @@ export default memo(({ header, className, children }) => {
? children
: (
<>
<SidebarItem icon='Home' text='Home' route='/vizality/dashboard' tooltip={collapsed && 'Home'} />
<SidebarItem icon='Gear' text='Settings' route='/vizality/settings' tooltip={collapsed && 'Settings'} />
<SidebarItem icon='Plugin' text='Plugins' route='/vizality/plugins' tooltip={collapsed && 'Plugins'} />
<SidebarItem icon='Theme' text='Themes' route='/vizality/themes' tooltip={collapsed && 'Themes'} />
<SidebarItem icon='Scissors' text='Snippets' route='/vizality/snippets' tooltip={collapsed && 'Snippets'} disabled />
<Item icon='House' route='/vizality/dashboard' tooltip={collapsed && 'Home'}>
Home
</Item>
<Item icon='Gear' route='/vizality/settings' tooltip={collapsed && 'Settings'}>
Settings
</Item>
<Item icon='Plugin' route='/vizality/plugins' tooltip={collapsed && 'Plugins'}>
Plugins
</Item>
<Item icon='Theme' route='/vizality/themes' tooltip={collapsed && 'Themes'}>
Themes
</Item>
<Item icon='Scissors' route='/vizality/snippets' tooltip={collapsed && 'Snippets'} disabled>
Snippets
</Item>
{vizality.manager.builtins.isEnabled('quick-code') && (
<SidebarItem icon='Compose' text='Quick Code' route='/vizality/quick-code' tooltip={collapsed && 'Quick Code'} />
<Item icon='Compose' route='/vizality/quick-code' tooltip={collapsed && 'Quick Code'}>
Quick Code
</Item>
)}
{/* @todo Addon Guidelines, Publish an Addon, Get Verified, Documentation, VSCode Snippets, Manifest Generator */}
<SidebarSeparator />
<SidebarItem icon='UnknownUser' text='Development' route='/vizality/development' tooltip={collapsed && 'Development'} disabled />
<SidebarSeparator />
<SidebarItem icon='CloudDownload' text='Updater' route='/vizality/updater' tooltip={collapsed && 'Updater'} />
<SidebarItem
icon='ClockReverse'
text='Changelog'
route='/vizality/changelog'
tooltip={collapsed && 'Changelog'}
/>
<Separator />
<Item icon='UnknownUser' route='/vizality/development' tooltip={collapsed && 'Development'} disabled>
Development
</Item>
<Separator />
<Item icon='CloudDownload' route='/vizality/updater' tooltip={collapsed && 'Updater'}>
Updater
</Item>
<Item icon='MoreInfo' route='/vizality/changelog' tooltip={collapsed && 'Changelog'}>
Changelog
</Item>
</>
)}
</AdvancedScrollerThin>

@ -6,3 +6,13 @@ export { default as Content } from './Content';
export { default as Section } from './Section';
export { default as Sidebar } from './Sidebar';
export { default as Layout } from './Layout';
import { Header as SidebarHeader, Item as SidebarItem, Separator as SidebarSeparator } from './Sidebar';
import { Header as SectionHeader } from './Section';
this.Sidebar.Separator = SidebarSeparator;
this.Sidebar.Header = SidebarHeader;
this.Sidebar.Item = SidebarItem;
this.Section.Header = SectionHeader;

Loading…
Cancel
Save