CB-3178: fix navigation tree tools styles (#1959)

* CB-3178: fix navigation tree tools styles

* CB-3178: refactoring css-modules

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
This commit is contained in:
Dmitriy Osipov
2023-08-29 12:22:01 +03:00
committed by GitHub
co-authored by Daria Marutkina
parent 7a3b17081c
commit 534b02d5ee
9 changed files with 154 additions and 121 deletions
@@ -0,0 +1,17 @@
.iconButton {
color: inherit;
outline: none;
border: none;
background: none;
cursor: pointer;
padding: 0;
margin: 4px;
height: 16px;
width: 16px;
& .icon,
& .staticImage {
width: 100%;
height: 100%;
}
}
+11 -26
View File
@@ -6,33 +6,16 @@
* you may not use this file except in compliance with the License.
*/
import { Button, ButtonProps } from 'reakit/Button';
import styled, { css } from 'reshadow';
import styled from 'reshadow';
import type { ComponentStyle } from '@cloudbeaver/core-theming';
import { Icon } from './Icon';
import { s } from './s';
import { StaticImage } from './StaticImage';
import { useS } from './useS';
import { useStyles } from './useStyles';
const styles = css`
Button {
color: inherit;
outline: none;
border: none;
background: none;
cursor: pointer;
padding: 0;
margin: 4px;
height: 16px;
width: 16px;
& Icon,
& StaticImage {
width: 100%;
height: 100%;
}
}
`;
import IconButtonStyles from './IconButton.m.css';
interface Props {
name: string;
@@ -41,11 +24,13 @@ interface Props {
style?: ComponentStyle;
}
export function IconButton({ name, img, viewBox, style, ...rest }: Props & ButtonProps) {
return styled(useStyles(styles, style))(
<Button {...rest}>
{img && <StaticImage icon={name} />}
{!img && <Icon name={name} viewBox={viewBox} />}
export function IconButton({ name, img, viewBox, style, className, ...rest }: Props & ButtonProps) {
const styles = useS(IconButtonStyles);
return styled(useStyles(style))(
<Button {...rest} className={s(styles, { iconButton: true }, className)}>
{img && <StaticImage className={s(styles, { staticImage: true })} icon={name} />}
{!img && <Icon className={s(styles, { icon: true })} name={name} viewBox={viewBox} />}
</Button>,
);
}
+1
View File
@@ -163,6 +163,7 @@ export * from './StatusMessage';
export * from './ExceptionMessage';
export * from './getComputed';
export * from './IconButton';
export { default as IconButtonStyles } from './IconButton.m.css';
export * from './IconOrImage';
export * from './s';
export * from './SContext';
@@ -0,0 +1,21 @@
.primary {
composes: theme-text-primary from global;
}
.tools {
composes: theme-background-surface from global;
display: block;
position: sticky;
top: 0;
z-index: 1;
}
.actions {
display: flex;
flex-direction: row;
overflow-x: auto;
}
.fill {
flex: 1;
}
@@ -7,63 +7,42 @@
*/
import { observer } from 'mobx-react-lite';
import React, { useState } from 'react';
import styled, { css, use } from 'reshadow';
import styled from 'reshadow';
import { ACTION_ICON_BUTTON_STYLES, IconButton, PlaceholderElement, useResource, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import {
ACTION_ICON_BUTTON_STYLES,
IconButton,
IconButtonStyles,
PlaceholderElement,
s,
SContext,
StyleRegistry,
useS,
useStyles,
useTranslate,
} from '@cloudbeaver/core-blocks';
import type { ComponentStyle } from '@cloudbeaver/core-theming';
import { useCaptureViewContext } from '@cloudbeaver/core-view';
import { DATA_CONTEXT_ELEMENTS_TREE } from '../DATA_CONTEXT_ELEMENTS_TREE';
import type { IElementsTree } from '../useElementsTree';
import { ElementsTreeFilter } from './ElementsTreeFilter';
import ElementsTreeToolsStyles from './ElementsTreeTools.m.css';
import ElementsTreeToolsIconButtonStyles from './ElementsTreeToolsIconButton.m.css';
import { ElementsTreeToolsMenu } from './ElementsTreeToolsMenu';
import { DATA_CONTEXT_NAV_TREE_ROOT } from './NavigationTreeSettings/DATA_CONTEXT_NAV_TREE_ROOT';
import type { IElementsTreeSettingsProps } from './NavigationTreeSettings/ElementsTreeSettingsService';
import { NavigationTreeSettings } from './NavigationTreeSettings/NavigationTreeSettings';
const toolsStyles = css`
[|primary] {
composes: theme-text-primary from global;
}
tools {
composes: theme-background-surface from global;
display: block;
position: sticky;
top: 0;
z-index: 1;
}
actions {
display: flex;
flex-direction: row;
}
fill {
flex: 1;
}
IconButton {
& Icon,
& StaticImage {
transition: transform 0.3s ease-in-out;
}
&[|opened] Icon,
&[|opened] StaticImage {
transform: rotate(180deg);
}
&[|loading] Icon,
&[|loading] StaticImage {
animation: rotating 1.5s linear infinite;
}
}
@keyframes rotating {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
`;
const registry: StyleRegistry = [
[
IconButtonStyles,
{
mode: 'append',
styles: [ElementsTreeToolsIconButtonStyles],
},
],
];
interface Props {
tree: IElementsTree;
@@ -75,7 +54,8 @@ export const ElementsTreeTools = observer<React.PropsWithChildren<Props>>(functi
const root = tree.root;
const translate = useTranslate();
const [opened, setOpen] = useState(false);
const styles = useStyles(ACTION_ICON_BUTTON_STYLES, toolsStyles, style);
const deprecatedStyles = useStyles(ACTION_ICON_BUTTON_STYLES, style);
const styles = useS(ElementsTreeToolsStyles, ElementsTreeToolsIconButtonStyles);
useCaptureViewContext(context => {
context?.set(DATA_CONTEXT_NAV_TREE_ROOT, tree.baseRoot);
@@ -84,34 +64,34 @@ export const ElementsTreeTools = observer<React.PropsWithChildren<Props>>(functi
const loading = tree.isLoading();
return styled(styles)(
<tools>
<actions>
{tree.settings?.configurable && (
return styled(deprecatedStyles)(
<SContext registry={registry}>
<tools className={s(styles, { tools: true })}>
<actions className={s(styles, { actions: true })}>
{tree.settings?.configurable && (
<IconButton
name="/icons/settings_cog_sm.svg"
title={translate('ui_settings')}
className={s(styles, { primary: true, opened })}
img
onClick={() => setOpen(!opened)}
/>
)}
<div className={s(styles, { fill: true })} />
<ElementsTreeToolsMenu tree={tree} />
<IconButton
name="/icons/settings_cog_sm.svg"
title={translate('ui_settings')}
style={toolsStyles}
name="/icons/refresh_sm.svg#root"
title={translate('app_navigationTree_refresh')}
disabled={loading}
className={s(styles, { primary: true, loading })}
img
onClick={() => setOpen(!opened)}
{...use({ opened, primary: true })}
onClick={() => tree.refresh(root)}
/>
)}
<fill />
<ElementsTreeToolsMenu tree={tree} />
<IconButton
name="/icons/refresh_sm.svg#root"
title={translate('app_navigationTree_refresh')}
style={toolsStyles}
disabled={loading}
img
onClick={() => tree.refresh(root)}
{...use({ primary: true, loading })}
/>
</actions>
{tree.settings && opened && <NavigationTreeSettings tree={tree} elements={settingsElements} style={style} />}
<ElementsTreeFilter tree={tree} style={style} />
{children}
</tools>,
</actions>
{tree.settings && opened && <NavigationTreeSettings tree={tree} elements={settingsElements} style={style} />}
<ElementsTreeFilter tree={tree} style={style} />
{children}
</tools>
</SContext>,
);
});
@@ -0,0 +1,29 @@
.iconButton {
& .icon,
& .staticImage {
transition: transform 0.3s ease-in-out;
}
&.loading {
& .icon,
& .staticImage {
animation: rotating 1.5s linear infinite;
}
}
&.opened {
& .icon,
& .staticImage {
transform: rotate(180deg);
}
}
}
@keyframes rotating {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@@ -0,0 +1,15 @@
.settings {
display: flex;
flex-direction: row;
overflow: auto;
}
.group {
min-width: fit-content;
margin-right: 0;
width: 100%;
}
.settings > .groupPadding {
padding: 12px;
}
@@ -6,27 +6,12 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Group, Loader, Placeholder, PlaceholderElement, useStyles } from '@cloudbeaver/core-blocks';
import { Group, Loader, Placeholder, PlaceholderElement, s, useS } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { ElementsTreeSettingsService, IElementsTreeSettingsProps } from './ElementsTreeSettingsService';
const expandStyles = css`
settings {
display: flex;
flex-direction: row;
}
Group {
min-width: 350px;
width: min-content;
&[dense] {
padding: 12px;
}
}
`;
import NavigationTreeSettingsStyles from './NavigationTreeSettings.m.css';
interface Props extends IElementsTreeSettingsProps {
elements?: PlaceholderElement<IElementsTreeSettingsProps>[];
@@ -34,16 +19,16 @@ interface Props extends IElementsTreeSettingsProps {
}
export const NavigationTreeSettings = observer<Props>(function NavigationTreeSettings({ elements, tree, style, className }) {
const styles = useStyles(expandStyles, style);
const elementsTreeSettingsService = useService(ElementsTreeSettingsService);
const styles = useS(NavigationTreeSettingsStyles);
return styled(styles)(
<settings className={className}>
<Group keepSize form gap dense>
return (
<div className={s(styles, { settings: true }, className)}>
<Group className={s(styles, { group: true, groupPadding: true })} keepSize gap dense>
<Loader suspense>
<Placeholder container={elementsTreeSettingsService.placeholder} elements={elements} tree={tree} style={style} />
</Loader>
</Group>
</settings>,
</div>
);
});
@@ -42,7 +42,7 @@ const navigationTreeStyles = css`
display: flex;
flex: 1;
flex-direction: column;
overflow: auto;
overflow: hidden;
}
ElementsTree {