diff --git a/.vscode/settings.json b/.vscode/settings.json index 3a4e57c664..c176db36b8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,6 @@ { "editor.tabSize": 2, "editor.formatOnSave": true, - "editor.linkedEditing": true, "task.autoDetect": "off", diff --git a/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionImageWithMaskSvg.m.css b/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionImageWithMaskSvg.m.css deleted file mode 100644 index 0f158389b2..0000000000 --- a/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionImageWithMaskSvg.m.css +++ /dev/null @@ -1,3 +0,0 @@ -.background { - fill: transparent; -} diff --git a/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionImageWithMaskSvg.tsx b/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionImageWithMaskSvg.tsx index 23014f2bdd..7906f0517a 100644 --- a/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionImageWithMaskSvg.tsx +++ b/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionImageWithMaskSvg.tsx @@ -7,9 +7,6 @@ */ import { GlobalConstants, isValidUrl } from '@cloudbeaver/core-utils'; -import { useS } from '../useS'; -import style from './ConnectionImageWithMaskSvg.m.css'; - interface Props { icon?: string; connected: boolean; @@ -21,7 +18,6 @@ interface Props { } export const ConnectionImageWithMaskSvg: React.FC = ({ icon, connected, maskId, size = 16, markerRadius = 4, paddingSize = 0, className }) => { - const styles = useS(style); if (!icon) { return null; } @@ -52,7 +48,6 @@ export const ConnectionImageWithMaskSvg: React.FC = ({ icon, connected, m mask={`url(#${maskId})`} /> - ); diff --git a/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts b/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts index 4759cd171f..db39c41229 100644 --- a/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts +++ b/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts @@ -49,10 +49,6 @@ export const BASE_CONTAINERS_STYLES = css` align-items: flex-start; } - &[flexEnd] { - align-items: flex-end; - } - &[center] { align-items: center; justify-content: center; @@ -68,7 +64,7 @@ export const BASE_CONTAINERS_STYLES = css` } &[parent] { - padding: 16px; + padding: 24px; &[compact] { padding: 16px; @@ -80,14 +76,14 @@ export const BASE_CONTAINERS_STYLES = css` } &[gap] { - gap: 16px; + gap: 24px; &[compact] { gap: 16px; } &[dense] { - gap: 16px; + gap: 8px; } } } @@ -95,7 +91,7 @@ export const BASE_CONTAINERS_STYLES = css` Group { align-content: baseline; box-sizing: border-box; - padding: 16px; + padding: 24px; border-radius: var(--theme-group-element-radius); &[dense] { @@ -221,7 +217,7 @@ export const BASE_CONTAINERS_STYLES = css` } Group[box] > GroupTitle { - padding: 16px; + padding: 24px; } GroupSubTitle { diff --git a/webapp/packages/core-blocks/src/Containers/IContainerProps.ts b/webapp/packages/core-blocks/src/Containers/IContainerProps.ts index f1349a2987..5839ff3f47 100644 --- a/webapp/packages/core-blocks/src/Containers/IContainerProps.ts +++ b/webapp/packages/core-blocks/src/Containers/IContainerProps.ts @@ -10,7 +10,6 @@ import type { ILayoutSizeProps } from './ILayoutSizeProps'; export interface IContainerProps extends ILayoutSizeProps { hideEmpty?: boolean; flexStart?: boolean; - flexEnd?: boolean; baseline?: boolean; center?: boolean; vertical?: boolean; diff --git a/webapp/packages/core-blocks/src/Containers/filterContainerFakeProps.ts b/webapp/packages/core-blocks/src/Containers/filterContainerFakeProps.ts index 4fa5846c44..acb850f498 100644 --- a/webapp/packages/core-blocks/src/Containers/filterContainerFakeProps.ts +++ b/webapp/packages/core-blocks/src/Containers/filterContainerFakeProps.ts @@ -9,7 +9,7 @@ import { filterLayoutFakeProps } from './filterLayoutFakeProps'; import type { IContainerProps } from './IContainerProps'; export function filterContainerFakeProps(props: T): Omit { - const { hideEmpty, flexStart, flexEnd, baseline, center, vertical, wrap, overflow, parent, gap, grid, dense, compact, ...rest } = + const { hideEmpty, flexStart, baseline, center, vertical, wrap, overflow, parent, gap, grid, dense, compact, ...rest } = filterLayoutFakeProps(props); return rest as Omit; diff --git a/webapp/packages/core-blocks/src/DisplayError.tsx b/webapp/packages/core-blocks/src/DisplayError.tsx index 6635e2e045..f3d130246c 100644 --- a/webapp/packages/core-blocks/src/DisplayError.tsx +++ b/webapp/packages/core-blocks/src/DisplayError.tsx @@ -29,7 +29,7 @@ const style = css` error-inner-block { display: flex; margin: auto; - padding: 8px 16px; + padding: 16px 24px; flex-direction: column; align-items: center; } diff --git a/webapp/packages/core-blocks/src/ExceptionMessage.tsx b/webapp/packages/core-blocks/src/ExceptionMessage.tsx index 4221a9794f..4fd80e2c96 100644 --- a/webapp/packages/core-blocks/src/ExceptionMessage.tsx +++ b/webapp/packages/core-blocks/src/ExceptionMessage.tsx @@ -21,7 +21,7 @@ const style = css` error { flex: 1; display: flex; - padding: 16px; + padding: 24px; } error-name { @@ -30,7 +30,6 @@ const style = css` text-overflow: ellipsis; overflow: hidden; white-space: nowrap; - margin: 0; & span { display: inline-block; @@ -149,7 +148,7 @@ export const ExceptionMessage = observer(function ExceptionMessage({ exce {!icon && ( <> - + {translate('core_blocks_exception_message_error_title')} diff --git a/webapp/packages/core-blocks/src/FormControls/BASE_DROPDOWN_STYLES.ts b/webapp/packages/core-blocks/src/FormControls/BASE_DROPDOWN_STYLES.ts index 569406b839..1f29199361 100644 --- a/webapp/packages/core-blocks/src/FormControls/BASE_DROPDOWN_STYLES.ts +++ b/webapp/packages/core-blocks/src/FormControls/BASE_DROPDOWN_STYLES.ts @@ -32,7 +32,7 @@ export const BASE_DROPDOWN_STYLES = css` outline: none; color: inherit; cursor: pointer; - gap: 16px; + gap: 8px; & item-icon, & item-title { diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.m.css b/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.m.css deleted file mode 100644 index c88e369e63..0000000000 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.m.css +++ /dev/null @@ -1,2 +0,0 @@ -.checkbox { -} diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx index 4acf4fd0ff..42c8ef1868 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx @@ -10,10 +10,7 @@ import styled, { css } from 'reshadow'; import type { ComponentStyle } from '@cloudbeaver/core-theming'; -import { s } from '../../s'; -import { useS } from '../../useS'; import { useStyles } from '../../useStyles'; -import CheckboxMarkupStyles from './CheckboxMarkup.m.css'; export type CheckboxMod = 'primary' | 'surface' | 'small'; @@ -98,8 +95,6 @@ interface ICheckboxMarkupProps extends Omit = function CheckboxMarkup({ id, label, @@ -112,7 +107,6 @@ export const CheckboxMarkup: React.FC = function CheckboxM readOnly, ...rest }) { - const styles = useS(CheckboxMarkupStyles); const checkboxRef = useRef(null); useLayoutEffect(() => { @@ -131,7 +125,7 @@ export const CheckboxMarkup: React.FC = function CheckboxM ), )( - + diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx index ac811b0e0d..e78b506ca6 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx @@ -13,11 +13,13 @@ import { isControlPresented } from '../isControlPresented'; import { Checkbox, CheckboxBaseProps, CheckboxType, ICheckboxControlledProps, ICheckboxObjectProps } from './Checkbox'; const style = css` + Checkbox { + margin: -10px; + } field { display: flex; align-items: center; white-space: pre-wrap; - height: 32px; & field-label { cursor: pointer; diff --git a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx index 02f636bca3..33d16c8f14 100644 --- a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx @@ -82,7 +82,7 @@ const styles = css` outline: none; color: inherit; cursor: pointer; - gap: 16px; + gap: 8px; & item-icon, & item-title { @@ -193,7 +193,7 @@ export const Combobox: ComboboxType = observer(function Combobox({ iconSelector, titleSelector, isDisabled, - onChange = () => {}, + onChange = () => { }, onSelect, onSwitch, ...rest diff --git a/webapp/packages/core-blocks/src/HTMLTemplates/sso.html.ejs b/webapp/packages/core-blocks/src/HTMLTemplates/sso.html.ejs index bdf9242b11..e16b59246d 100644 --- a/webapp/packages/core-blocks/src/HTMLTemplates/sso.html.ejs +++ b/webapp/packages/core-blocks/src/HTMLTemplates/sso.html.ejs @@ -13,7 +13,7 @@ header { flex-grow: 0; flex-shrink: 0; - height: 32px; + height: 48px; padding: 0 16px; background-color: #2a7cb4; display: flex; @@ -21,8 +21,8 @@ } .logo { - height: 24px; - width: 120px; + height: 34px; + width: 154px; } .content { @@ -45,12 +45,16 @@
-

Authorization was successful.

-

Now you can close this page.

+

+ Authorization was successful. +

+

+ Now you can close this page. +

+ \ No newline at end of file diff --git a/webapp/packages/core-blocks/src/InfoItem.tsx b/webapp/packages/core-blocks/src/InfoItem.tsx index b09d53b91a..e4f31ec551 100644 --- a/webapp/packages/core-blocks/src/InfoItem.tsx +++ b/webapp/packages/core-blocks/src/InfoItem.tsx @@ -31,7 +31,7 @@ const styles = css` IconOrImage { width: 24px; height: 24px; - margin-right: 8px; + margin-right: 16px; } `; diff --git a/webapp/packages/core-blocks/src/ItemList/styles.ts b/webapp/packages/core-blocks/src/ItemList/styles.ts index 37960b706a..8a1ff690e3 100644 --- a/webapp/packages/core-blocks/src/ItemList/styles.ts +++ b/webapp/packages/core-blocks/src/ItemList/styles.ts @@ -39,7 +39,7 @@ export const ITEM_LIST_STYLES = css` composes: theme-background-surface theme-text-on-surface theme-typography--body1 from global; position: sticky; top: 0; - padding: 8px 16px; + padding: 16px 24px; z-index: 1; & input-box { @@ -83,13 +83,13 @@ export const ITEM_LIST_STYLES = css` display: flex; box-sizing: border-box; align-items: center; - padding: 0 8px; + padding: 0 16px; } list-item-icon { display: flex; align-items: center; box-sizing: border-box; - padding: 4px; + padding: 8px; & StaticImage { box-sizing: border-box; @@ -101,7 +101,7 @@ export const ITEM_LIST_STYLES = css` box-sizing: border-box; font-weight: 500; min-width: 250px; - padding: 4px 16px 4px 8px; + padding: 8px 24px 8px 8px; border-right: 1px solid; white-space: nowrap; @@ -112,7 +112,7 @@ export const ITEM_LIST_STYLES = css` composes: theme-typography--body2 from global; box-sizing: border-box; max-width: 460px; - padding: 4px 8px 4px 16px; + padding: 8px 8px 8px 24px; white-space: nowrap; overflow: hidden; diff --git a/webapp/packages/core-blocks/src/Menu/Menu.m.css b/webapp/packages/core-blocks/src/Menu/Menu.m.css deleted file mode 100644 index 851b929b69..0000000000 --- a/webapp/packages/core-blocks/src/Menu/Menu.m.css +++ /dev/null @@ -1,28 +0,0 @@ -.menuButton { - composes: theme-ripple from global; -} -.menuButton { - background: none; - border: none; - outline: none !important; - color: inherit; - cursor: pointer; - - & .box { - display: flex; - align-items: center; - flex: 1; - height: inherit; - } -} -.menuButtonLink { - position: absolute; - width: 0; - height: 0; - overflow: hidden; - box-sizing: border-box; - padding: 0; - margin: 0; - border: none; - background: transparent; -} diff --git a/webapp/packages/core-blocks/src/Menu/Menu.tsx b/webapp/packages/core-blocks/src/Menu/Menu.tsx index dd2e12855c..eb4f09a45f 100644 --- a/webapp/packages/core-blocks/src/Menu/Menu.tsx +++ b/webapp/packages/core-blocks/src/Menu/Menu.tsx @@ -8,22 +8,25 @@ import { observer } from 'mobx-react-lite'; import React, { forwardRef, useLayoutEffect, useRef, useState } from 'react'; import { MenuButton, MenuInitialState, useMenuState } from 'reakit/Menu'; +import styled from 'reshadow'; + +import type { ComponentStyle } from '@cloudbeaver/core-theming'; import { ErrorBoundary } from '../ErrorBoundary'; -import { s } from '../s'; import { useCombinedRef } from '../useCombinedRef'; import { useObjectRef } from '../useObjectRef'; -import { useS } from '../useS'; -import style from './Menu.m.css'; +import { useStyles } from '../useStyles'; import { MenuPanel } from './MenuPanel'; +import { menuPanelStyles } from './menuPanelStyles'; import { IMenuState, MenuStateContext } from './MenuStateContext'; import type { IMouseContextMenu } from './useMouseContextMenu'; -interface IMenuProps extends React.ButtonHTMLAttributes { +interface IMenuProps extends Omit, 'style'> { mouseContextMenu?: IMouseContextMenu; label: string; items: React.ReactNode | (() => React.ReactNode); menuRef?: React.RefObject; + style?: ComponentStyle; disclosure?: boolean; placement?: MenuInitialState['placement']; submenu?: boolean; @@ -45,6 +48,7 @@ export const Menu = observer( menuRef, disclosure, children, + style, placement, visible, hasBindings, @@ -54,7 +58,6 @@ export const Menu = observer( modal, submenu, rtl, - className, ...props }, ref, @@ -71,7 +74,7 @@ export const Menu = observer( visible, rtl, }); - const styles = useS(style); + const styles = useStyles(menuPanelStyles, style); if (menuRef) { //@ts-expect-error Ref mutation @@ -127,24 +130,17 @@ export const Menu = observer( const MenuButtonLink = MenuButton; if (React.isValidElement(children) && disclosure) { - return ( + return styled(styles)( - + {disclosureProps => React.cloneElement(children, { ...disclosureProps, ...children.props })} ( > {items} - {relativePosition && ( - - )} + {relativePosition && } - + , ); } - return ( + return styled(styles)( - -
{children}
+ + {children} ( > {items} - {relativePosition && ( - - )} + {relativePosition && }
-
+ , ); }), ); diff --git a/webapp/packages/core-blocks/src/Menu/MenuEmptyItem.tsx b/webapp/packages/core-blocks/src/Menu/MenuEmptyItem.tsx index 8607665370..f2a825498d 100644 --- a/webapp/packages/core-blocks/src/Menu/MenuEmptyItem.tsx +++ b/webapp/packages/core-blocks/src/Menu/MenuEmptyItem.tsx @@ -6,19 +6,29 @@ * you may not use this file except in compliance with the License. */ import { observer } from 'mobx-react-lite'; +import styled from 'reshadow'; + +import type { ComponentStyle } from '@cloudbeaver/core-theming'; import { useTranslate } from '../localization/useTranslate'; +import { useStyles } from '../useStyles'; import { MenuItem } from './MenuItem'; import { MenuItemElement } from './MenuItemElement'; +import { menuPanelStyles } from './menuPanelStyles'; -export const MenuEmptyItem = observer(function MenuEmptyItem() { +interface Props extends Omit, 'style'> { + style?: ComponentStyle; +} + +export const MenuEmptyItem = observer(function MenuEmptyItem({ style }) { + const styles = useStyles(menuPanelStyles, style); const translate = useTranslate(); const label = translate('core_ui_empty'); - return ( - - - + return styled(styles)( + + + , ); }); diff --git a/webapp/packages/core-blocks/src/Menu/MenuItem.m.css b/webapp/packages/core-blocks/src/Menu/MenuItem.m.css deleted file mode 100644 index 0b74547cfc..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuItem.m.css +++ /dev/null @@ -1,23 +0,0 @@ -.menuItem { - composes: theme-ripple from global; - composes: menuItem from './MenuItemElement.m.css'; - - display: flex; - align-items: center; - border: none; - padding: 0; - background: none; - text-align: left; - outline: none; - color: inherit; - cursor: pointer; - white-space: nowrap; - - &.hidden { - display: none; - } - - &:global([aria-selected='true']) { - opacity: 0.7; - } -} diff --git a/webapp/packages/core-blocks/src/Menu/MenuItem.tsx b/webapp/packages/core-blocks/src/Menu/MenuItem.tsx index c7fcfa0678..cc894dde3d 100644 --- a/webapp/packages/core-blocks/src/Menu/MenuItem.tsx +++ b/webapp/packages/core-blocks/src/Menu/MenuItem.tsx @@ -8,44 +8,46 @@ import { observer } from 'mobx-react-lite'; import React, { useContext } from 'react'; import { MenuItem as ReakitMenuItem } from 'reakit/Menu'; -import type { CompositeItemOptions } from 'reakit/ts'; +import styled, { use } from 'reshadow'; + +import type { ComponentStyle } from '@cloudbeaver/core-theming'; -import { s } from '../s'; import { useCombinedHandler } from '../useCombinedHandler'; -import { useS } from '../useS'; -import style from './MenuItem.m.css'; +import { useStyles } from '../useStyles'; +import { menuPanelStyles } from './menuPanelStyles'; import { MenuStateContext } from './MenuStateContext'; -import type { ReakitProxyComponent, ReakitProxyComponentOptions } from './ReakitProxyComponent'; -export type MenuItemOptions = CompositeItemOptions & { +export interface IMenuItemProps extends Omit, 'style'> { + label: string; + hidden?: boolean; selected?: boolean; close?: boolean; -}; + style?: ComponentStyle; +} -export const MenuItem: ReakitProxyComponent<'button', MenuItemOptions> = observer>( - function MenuItem({ children, hidden, selected, close, onClick, className, ...rest }) { - const menu = useContext(MenuStateContext); - const styles = useS(style); +export const MenuItem = observer(function MenuItem({ label, children, hidden, selected, close, style, onClick, ...rest }) { + const menu = useContext(MenuStateContext); + const styles = useStyles(menuPanelStyles, style); - const handleClick = useCombinedHandler<[React.MouseEvent]>(onClick, function handleClick() { - if (close) { - menu?.hide(); - } - }); + const handleClick = useCombinedHandler<[React.MouseEvent]>(onClick, function handleClick() { + if (close) { + menu?.hide(); + } + }); - const MenuItem = ReakitMenuItem; + const MenuItem = ReakitMenuItem; - return ( - - ); - }, -); + return styled(styles)( + , + ); +}); diff --git a/webapp/packages/core-blocks/src/Menu/MenuItemCheckbox.tsx b/webapp/packages/core-blocks/src/Menu/MenuItemCheckbox.tsx deleted file mode 100644 index 74cdd57dd1..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuItemCheckbox.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2023 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import { observer } from 'mobx-react-lite'; -import { useContext } from 'react'; -import { MenuItemOptions, MenuItemCheckbox as ReakitMenuItemCheckbox } from 'reakit/Menu'; -import type { CheckboxOptions } from 'reakit/ts'; - -import { s } from '../s'; -import { useS } from '../useS'; -import style from './MenuItem.m.css'; -import { MenuStateContext } from './MenuStateContext'; -import type { ReakitProxyComponent, ReakitProxyComponentOptions } from './ReakitProxyComponent'; - -type Options = CheckboxOptions & MenuItemOptions; - -export const MenuItemCheckbox: ReakitProxyComponent<'button', Options> = observer>( - function MenuItemCheckbox({ hidden, children, className, ...rest }) { - const menu = useContext(MenuStateContext); - const styles = useS(style); - - const MenuItemCheckbox = ReakitMenuItemCheckbox; - - return ( - - ); - }, -); diff --git a/webapp/packages/core-blocks/src/Menu/MenuItemElement.m.css b/webapp/packages/core-blocks/src/Menu/MenuItemElement.m.css deleted file mode 100644 index e7bf19eb1e..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuItemElement.m.css +++ /dev/null @@ -1,70 +0,0 @@ -.menuPanelItem { - composes: theme-ripple theme-border-color-background from global; - - flex: 1; - display: flex; - position: relative; - align-items: center; - height: 26px; - padding: 0 4px; - - & .menuItemText, - & .menuItemBinding { - display: block; - padding: 0 4px; - } - & .menuItemBinding { - flex: 1; - text-align: right; - padding-left: 32px; - width: 80px; - overflow: hidden; - text-overflow: ellipsis; - } - & .menuItemIcon, - & .menuItemContent { - width: 24px; - height: 24px; - overflow: hidden; - display: flex; - align-items: center; - justify-content: center; - } - & .menuItemContent .icon { - width: 10px; - height: 10px; - opacity: 0.5; - } - & .iconOrImage { - width: 16px; - height: 16px; - object-fit: contain; - } - & .loader { - width: 16px; - } -} - -.menuItemBinding { - composes: theme-typography--caption from global; -} - -.menuBox:not([data-s-has-bindings='true']) .menuItemBinding { - width: 0; -} - -.menuBox[dir='rtl'] { - & .menuItemText { - text-align: right; - } - & .menuItemContent .icon { - transform: rotate(180deg); - } -} - -.menuItem:hover, -.menuItem:global([aria-expanded='true']) { - & .menuItemContent .icon { - opacity: 1; - } -} diff --git a/webapp/packages/core-blocks/src/Menu/MenuItemElement.tsx b/webapp/packages/core-blocks/src/Menu/MenuItemElement.tsx index 2f9ca942e8..d64a384e7f 100644 --- a/webapp/packages/core-blocks/src/Menu/MenuItemElement.tsx +++ b/webapp/packages/core-blocks/src/Menu/MenuItemElement.tsx @@ -6,15 +6,17 @@ * you may not use this file except in compliance with the License. */ import { observer } from 'mobx-react-lite'; +import styled from 'reshadow'; + +import type { ComponentStyle } from '@cloudbeaver/core-theming'; import { Icon } from '../Icon'; import { IconOrImage } from '../IconOrImage'; import { Loader } from '../Loader/Loader'; import { useTranslate } from '../localization/useTranslate'; -import { s } from '../s'; -import { useS } from '../useS'; import { useStateDelay } from '../useStateDelay'; -import style from './MenuItemElement.m.css'; +import { useStyles } from '../useStyles'; +import { menuPanelStyles } from './menuPanelStyles'; interface IMenuItemElementProps { label: string; @@ -26,6 +28,7 @@ interface IMenuItemElementProps { menu?: boolean; loading?: boolean; panelAvailable?: boolean; + style?: ComponentStyle; } export const MenuItemElement = observer(function MenuItemElement({ @@ -37,34 +40,22 @@ export const MenuItemElement = observer(function MenuItem menu, panelAvailable, loading = false, + style = [], }) { - const styles = useS(style); const translate = useTranslate(); const title = translate(label); loading = useStateDelay(loading, 100); - return ( -
-
- - {typeof icon === 'string' ? : icon} - -
- {displayLabel ? ( -
- {title} -
- ) : ( -
- )} -
- {binding} -
-
- {loading && } - {panelAvailable !== false && menu && !loading && } -
-
+ return styled(useStyles(menuPanelStyles, style))( + + {typeof icon === 'string' ? : icon} + {displayLabel ? {title} : } + {binding} + + {loading && } + {panelAvailable !== false && menu && !loading && } + + , ); }); diff --git a/webapp/packages/core-blocks/src/Menu/MenuItemRadio.tsx b/webapp/packages/core-blocks/src/Menu/MenuItemRadio.tsx deleted file mode 100644 index 4109d6af2e..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuItemRadio.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2023 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import { observer } from 'mobx-react-lite'; -import { useContext } from 'react'; -import { MenuItemOptions, MenuItemRadio as ReakitMenuItemRadio } from 'reakit/Menu'; -import type { RadioOptions } from 'reakit/ts'; - -import { s } from '../s'; -import { useS } from '../useS'; -import style from './MenuItem.m.css'; -import { MenuStateContext } from './MenuStateContext'; -import type { ReakitProxyComponent, ReakitProxyComponentOptions } from './ReakitProxyComponent'; - -type Options = RadioOptions & MenuItemOptions; - -export const MenuItemRadio: ReakitProxyComponent<'button', Options> = observer>( - function MenuItemRadio({ hidden, children, className, ...rest }) { - const menu = useContext(MenuStateContext); - const styles = useS(style); - - const MenuItemRadio = ReakitMenuItemRadio; - - return ( - - ); - }, -); diff --git a/webapp/packages/core-blocks/src/Menu/MenuPanel.m.css b/webapp/packages/core-blocks/src/Menu/MenuPanel.m.css deleted file mode 100644 index de1841b4fe..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuPanel.m.css +++ /dev/null @@ -1,27 +0,0 @@ -.menu { - outline: none; - z-index: 999; -} -.menuBox { - composes: theme-background-surface theme-text-on-surface theme-group-element-radius theme-typography--caption theme-elevation-z5 from global; - composes: menuBox from './MenuItemElement.m.css'; - - display: flex; - flex-direction: column; - min-width: 140px; - padding: 6px 0; - - & .menuBox { - margin-top: -6px; - } -} - -.menu.modal .menuBox { - overflow: auto; - max-height: 80vh; - overflow-x: hidden; -} - -.menu.submenu { - margin-top: -6px; -} diff --git a/webapp/packages/core-blocks/src/Menu/MenuPanel.tsx b/webapp/packages/core-blocks/src/Menu/MenuPanel.tsx index 245d35b7cc..a58f87c6a1 100644 --- a/webapp/packages/core-blocks/src/Menu/MenuPanel.tsx +++ b/webapp/packages/core-blocks/src/Menu/MenuPanel.tsx @@ -8,13 +8,15 @@ import { observer } from 'mobx-react-lite'; import { Children, forwardRef } from 'react'; import { Menu, MenuStateReturn } from 'reakit/Menu'; +import styled, { use } from 'reshadow'; + +import type { ComponentStyle } from '@cloudbeaver/core-theming'; import { ErrorBoundary } from '../ErrorBoundary'; import { getComputed } from '../getComputed'; -import { s } from '../s'; -import { useS } from '../useS'; +import { useStyles } from '../useStyles'; import { MenuEmptyItem } from './MenuEmptyItem'; -import style from './MenuPanel.m.css'; +import { menuPanelStyles } from './menuPanelStyles'; export interface IMenuPanelProps { label: string; @@ -25,12 +27,13 @@ export interface IMenuPanelProps { children: React.ReactNode | (() => React.ReactNode); rtl?: boolean; submenu?: boolean; + style?: ComponentStyle; className?: string; } export const MenuPanel = observer( - forwardRef(function MenuPanel({ label, menu, submenu, panelAvailable = true, rtl, getHasBindings, hasBindings, children, className }, ref) { - const styles = useS(style); + forwardRef(function MenuPanel({ label, menu, panelAvailable = true, rtl, getHasBindings, hasBindings, children, style, className }, ref) { + const styles = useStyles(menuPanelStyles, style); const visible = menu.visible; if (!visible) { @@ -45,21 +48,15 @@ export const MenuPanel = observer( renderedChildren = typeof children === 'function' ? children() : children; } - return ( + return styled(styles)( - -
- {Children.count(renderedChildren) === 0 && } + + + {Children.count(renderedChildren) === 0 && } {renderedChildren} -
+
-
+ , ); }), ); diff --git a/webapp/packages/core-blocks/src/Menu/MenuSeparator.m.css b/webapp/packages/core-blocks/src/Menu/MenuSeparator.m.css deleted file mode 100644 index a7ceb5aa90..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuSeparator.m.css +++ /dev/null @@ -1,11 +0,0 @@ -.menuSeparator { - flex: 1; - width: 100%; - display: flex; - margin: 4px 0; - - &:first-child, - &:last-child { - display: none; - } -} diff --git a/webapp/packages/core-blocks/src/Menu/MenuSeparator.tsx b/webapp/packages/core-blocks/src/Menu/MenuSeparator.tsx deleted file mode 100644 index 0af23f447a..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuSeparator.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2023 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import { MenuSeparator as MenuSeparatorBase } from 'reakit/Menu'; -import type { SeparatorOptions } from 'reakit/ts'; - -import { s } from '../s'; -import { useS } from '../useS'; -import style from './MenuSeparator.m.css'; -import type { ReakitProxyComponentOptions } from './ReakitProxyComponent'; - -export const MenuSeparator = function MenuSeparator({ className, ...props }: ReakitProxyComponentOptions<'hr', SeparatorOptions>) { - const styles = useS(style); - return ; -}; diff --git a/webapp/packages/core-blocks/src/Menu/ReakitProxyComponent.ts b/webapp/packages/core-blocks/src/Menu/ReakitProxyComponent.ts deleted file mode 100644 index 6f5c507b9f..0000000000 --- a/webapp/packages/core-blocks/src/Menu/ReakitProxyComponent.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2023 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import type { ReactElement } from 'react'; -import type { As, PropsWithAs } from 'reakit-utils/types'; - -export type ReakitProxyPropsWithAs = Omit, 'children'> & { - children?: React.ReactNode; -}; - -export type ReakitProxyComponentOptions = ReakitProxyPropsWithAs; - -export type ReakitProxyComponent = { - ( - props: ReakitProxyPropsWithAs & { - as: TT; - }, - context?: any, - ): ReactElement | null; - (props: ReakitProxyPropsWithAs, context?: any): ReactElement | null; -}; diff --git a/webapp/packages/core-blocks/src/Menu/menuPanelStyles.ts b/webapp/packages/core-blocks/src/Menu/menuPanelStyles.ts new file mode 100644 index 0000000000..137cd3d6c6 --- /dev/null +++ b/webapp/packages/core-blocks/src/Menu/menuPanelStyles.ts @@ -0,0 +1,186 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { css } from 'reshadow'; + +export const menuPanelStyles = css` + menu-box { + composes: theme-background-surface theme-text-on-surface from global; + } + MenuItem, + MenuItemCheckbox, + MenuItemRadio, + MenuButton, + MenuItemElement { + composes: theme-ripple from global; + } + menu-panel-item, + MenuSeparator { + composes: theme-border-color-background from global; + } + MenuButton { + background: none; + border: none; + outline: none !important; + color: inherit; + cursor: pointer; + & box { + display: flex; + align-items: center; + flex: 1; + height: inherit; + } + } + MenuButtonLink { + position: absolute; + width: 0; + height: 0; + overflow: hidden; + box-sizing: border-box; + padding: 0; + margin: 0; + border: none; + background: transparent; + } + Menu { + outline: none; + z-index: 999; + } + MenuPanel[submenu] { + margin-top: -6px; + } + menu-box { + composes: theme-group-element-radius theme-typography--body2 theme-elevation-z5 from global; + min-width: 140px; + padding: 6px 0; + + & menu-box { + margin-top: -6px; + } + } + + menu-box { + display: flex; + flex-direction: column; + + &:not([|hasBindings]) menu-item-binding { + width: 0; + } + } + + Menu[modal] menu-box { + overflow: auto; + max-height: 80vh; + overflow-x: hidden; + } + + MenuItem, + MenuItemCheckbox, + MenuItemRadio { + display: flex; + align-items: center; + border: none; + padding: 0; + background: none; + text-align: left; + outline: none; + color: inherit; + cursor: pointer; + white-space: nowrap; + + &[use|hidden] { + display: none; + } + + &:global([aria-selected='true']) { + opacity: 0.7; + } + + &:hover, + &:global([aria-expanded='true']) { + & Icon { + opacity: 1; + } + } + } + + MenuSeparator { + flex: 1; + width: 100%; + display: flex; + margin: 6px 0; + border: none !important; + border-bottom: 1px solid !important; + + &:first-child, + &:last-child { + display: none; + } + } + + menu-item-binding { + composes: theme-typography--caption from global; + } + + menu-panel-item { + flex: 1; + display: flex; + position: relative; + align-items: center; + height: 30px; + padding: 0 4px; + + & menu-item-text, + & menu-item-binding { + display: block; + padding: 0 4px; + } + & menu-item-binding { + flex: 1; + text-align: right; + padding-left: 32px; + width: 80px; + overflow: hidden; + text-overflow: ellipsis; + } + & menu-item-icon, + & menu-item-content { + width: 24px; + height: 24px; + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; + } + & menu-item-content Icon { + width: 10px; + height: 10px; + } + & Icon { + width: 16px; + height: 16px; + opacity: 0.5; + } + & IconOrImage { + width: 16px; + height: 16px; + object-fit: contain; + } + & Loader { + width: 16px; + } + } + + Menu[rtl] { + & menu-item-text { + text-align: right; + } + & menu-panel-item menu-item-content Icon { + transform: rotate(180deg); + } + } +`; diff --git a/webapp/packages/core-blocks/src/Overlay/OVERLAY_BASE_STYLES.ts b/webapp/packages/core-blocks/src/Overlay/OVERLAY_BASE_STYLES.ts index bdd375733f..46317c1020 100644 --- a/webapp/packages/core-blocks/src/Overlay/OVERLAY_BASE_STYLES.ts +++ b/webapp/packages/core-blocks/src/Overlay/OVERLAY_BASE_STYLES.ts @@ -60,7 +60,7 @@ export const OVERLAY_BASE_STYLES = css` message, actions { flex-shrink: 0; - padding: 16px; + padding: 24px; } message { diff --git a/webapp/packages/core-blocks/src/PropertiesTable/PropertyItem.tsx b/webapp/packages/core-blocks/src/PropertiesTable/PropertyItem.tsx index 70ad8f9f2e..a1e45cc736 100644 --- a/webapp/packages/core-blocks/src/PropertiesTable/PropertyItem.tsx +++ b/webapp/packages/core-blocks/src/PropertiesTable/PropertyItem.tsx @@ -37,7 +37,7 @@ const styles = css` align-items: center; box-sizing: border-box; flex: 1; - padding: 2px 0; + padding: 4px 0; & ShadowInput { height: 24px; diff --git a/webapp/packages/core-blocks/src/SContext.tsx b/webapp/packages/core-blocks/src/SContext.tsx deleted file mode 100644 index a0ca3d8437..0000000000 --- a/webapp/packages/core-blocks/src/SContext.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2023 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import React, { createContext } from 'react'; - -import type { IStyleRegistry, Style } from '@cloudbeaver/core-theming'; - -type Registry = Map; - -export type StyleRegistry = [Style, IStyleRegistry][]; - -export const SContextReact = createContext(new Map()); - -type Props = { - registry: StyleRegistry; -}; - -export const SContext: React.FC> = function SContext({ registry, children }) { - const context = React.useContext(SContextReact); - const state = new Map(context.entries()); - - for (const [style, styles] of registry) { - state.set(style, [...(state.get(style) || []), styles]); - } - - return {children}; -}; diff --git a/webapp/packages/core-blocks/src/Split/SplitControls.m.css b/webapp/packages/core-blocks/src/Split/SplitControls.m.css deleted file mode 100644 index 2f2c587725..0000000000 --- a/webapp/packages/core-blocks/src/Split/SplitControls.m.css +++ /dev/null @@ -1,123 +0,0 @@ -.container { - position: absolute; - display: flex; - justify-content: center; - align-content: center; - align-items: center; - - /* pointer outline */ - &::before { - content: ''; - position: absolute; - background: transparent; - } -} - -.button { - composes: theme-button theme-button_unelevated theme-button_background theme-elevation-z3 from global; - opacity: 0; - transition-property: opacity, box-shadow !important; - transition: opacity 0.3s ease-in-out; -} - -.ripple { - composes: theme-button_ripple from global; -} - -.container:hover .button { - opacity: 1; -} - -.container[data-s-split='vertical'] { - flex-direction: column; - cursor: ew-resize; - height: 100%; - width: 5px; - left: -2px; - - &[data-s-mode='minimize'] { - left: 0; - } - - &[data-s-mode='maximize'] { - left: -2px; - } - - & .button { - margin: 8px 0; - min-width: 16px; - - &::after { - transform: rotate(180deg); - } - } - - &[data-s-mode='maximize'] .button, - &[data-s-mode='minimize'] .button { - min-height: 64px; - } - - & .button.primary::after { - transform: rotate(0deg); - } -} - -.container[data-s-split='vertical'].inverse { - flex-direction: column-reverse; -} - -.container[data-s-split='horizontal'] { - flex-direction: row; - cursor: ns-resize; - width: 100%; - height: 5px; - top: -2px; - - &[data-s-mode='minimize'] { - top: 0; - } - - &[data-s-mode='maximize'] { - top: -2px; - } - - & .button { - margin: 0 8px; - min-width: 28px; - height: 16px; - - &::after { - transform: rotate(270deg); - } - } - - &[data-s-mode='maximize'] .button, - &[data-s-mode='minimize'] .button { - min-width: 64px; - } - - & .button.primary::after { - transform: rotate(90deg); - } -} - -.container[data-s-split='horizontal'].inverse { - flex-direction: row-reverse; -} - -.button { - padding: 0 !important; - &::after { - position: absolute; - top: 50%; - left: 50%; - content: ''; - display: block; - width: 0; - height: 0; - border-style: solid; - border-width: 3px 4px 3px 0; - border-color: transparent #000 transparent transparent; - margin: -3px -2px; - } -} diff --git a/webapp/packages/core-blocks/src/Split/SplitControls.tsx b/webapp/packages/core-blocks/src/Split/SplitControls.tsx index a489ab322a..f60063a3c0 100644 --- a/webapp/packages/core-blocks/src/Split/SplitControls.tsx +++ b/webapp/packages/core-blocks/src/Split/SplitControls.tsx @@ -5,15 +5,14 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import { s } from '../s'; +import styled, { use } from 'reshadow'; + import { useObjectRef } from '../useObjectRef'; -import { useS } from '../useS'; -import SplitControlsStyles from './SplitControls.m.css'; +import { buttonStyles } from './splitButtonStyles'; import { useSplit } from './useSplit'; export const SplitControls: React.FC = function SplitControls() { const split = useSplit(); - const styles = useS(SplitControlsStyles); const inverse = split.state.isMainSecond(); @@ -52,27 +51,25 @@ export const SplitControls: React.FC = function SplitControls() { ['handleCollapse', 'handleExpand'], ); - return ( -
{split.state.mode !== 'minimize' && ( - )} {split.state.mode !== 'maximize' && ( - )} -
+ , ); }; diff --git a/webapp/packages/core-blocks/src/Split/splitButtonStyles.ts b/webapp/packages/core-blocks/src/Split/splitButtonStyles.ts new file mode 100644 index 0000000000..2c23461da5 --- /dev/null +++ b/webapp/packages/core-blocks/src/Split/splitButtonStyles.ts @@ -0,0 +1,131 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { css } from 'reshadow'; + +export const buttonStyles = css` + container { + position: absolute; + display: flex; + justify-content: center; + align-content: center; + align-items: center; + + /* pointer outline */ + &::before { + content: ''; + position: absolute; + background: transparent; + } + } + + button { + composes: theme-button theme-button_unelevated theme-button_background theme-elevation-z3 from global; + opacity: 0; + transition-property: opacity, box-shadow !important; + transition: opacity 0.3s ease-in-out; + } + + ripple { + composes: theme-button_ripple from global; + } + + container:hover button { + opacity: 1; + } + + container[|split='vertical'] { + flex-direction: column; + cursor: ew-resize; + height: 100%; + width: 5px; + left: -2px; + + &[|mode='minimize'] { + left: 0; + } + + &[|mode='maximize'] { + left: -2px; + } + + & button { + margin: 8px 0; + min-width: 16px; + + &::after { + transform: rotate(180deg); + } + } + + &[|mode='maximize'] button, + &[|mode='minimize'] button { + min-height: 64px; + } + + & button[|isPrimary]::after { + transform: rotate(0deg); + } + } + container[|split='vertical'][|inverse] { + flex-direction: column-reverse; + } + + container[|split='horizontal'] { + flex-direction: row; + cursor: ns-resize; + width: 100%; + height: 5px; + top: -2px; + + &[|mode='minimize'] { + top: 0; + } + + &[|mode='maximize'] { + top: -2px; + } + + & button { + margin: 0 8px; + min-width: 28px; + height: 16px; + + &::after { + transform: rotate(270deg); + } + } + + &[|mode='maximize'] button, + &[|mode='minimize'] button { + min-width: 64px; + } + + & button[|isPrimary]::after { + transform: rotate(90deg); + } + } + container[|split='horizontal'][|inverse] { + flex-direction: row-reverse; + } + button { + padding: 0 !important; + &::after { + position: absolute; + top: 50%; + left: 50%; + content: ''; + display: block; + width: 0; + height: 0; + border-style: solid; + border-width: 3px 4px 3px 0; + border-color: transparent #000 transparent transparent; + margin: -3px -2px; + } + } +`; diff --git a/webapp/packages/core-blocks/src/Table/BASE_TABLE_STYLES.ts b/webapp/packages/core-blocks/src/Table/BASE_TABLE_STYLES.ts index ad6e0d6670..dbb24634d9 100644 --- a/webapp/packages/core-blocks/src/Table/BASE_TABLE_STYLES.ts +++ b/webapp/packages/core-blocks/src/Table/BASE_TABLE_STYLES.ts @@ -35,15 +35,15 @@ export const BASE_TABLE_STYLES = css` &[|size='big'] { & > thead > tr > th { - height: 36px; + height: 54px; &[|min] { - width: 32px; + width: 46px; } } & > tbody > tr > td { - height: 32px; + height: 46px; } } @@ -83,7 +83,7 @@ export const BASE_TABLE_STYLES = css` th { box-sizing: border-box; white-space: nowrap; - padding: 8px; + padding: 16px; height: 36px; padding-top: unset; padding-bottom: unset; @@ -114,7 +114,7 @@ export const BASE_TABLE_STYLES = css` position: relative; box-sizing: border-box; height: 28px; - padding: 0 8px; + padding: 0 16px; transition: padding ease-in-out 0.24s; &[|ellipsis] { diff --git a/webapp/packages/core-blocks/src/Table/TableItemSelect.tsx b/webapp/packages/core-blocks/src/Table/TableItemSelect.tsx index f7cd8f9c44..56287d3465 100644 --- a/webapp/packages/core-blocks/src/Table/TableItemSelect.tsx +++ b/webapp/packages/core-blocks/src/Table/TableItemSelect.tsx @@ -26,8 +26,8 @@ interface Props { const checkboxStyles = css` Checkbox { - margin-left: -6px; - margin-right: -6px; + margin-left: -10px; + margin-right: -10px; } `; diff --git a/webapp/packages/core-blocks/src/Table/TableSelect.tsx b/webapp/packages/core-blocks/src/Table/TableSelect.tsx index 82f882097e..6bc441f8e0 100644 --- a/webapp/packages/core-blocks/src/Table/TableSelect.tsx +++ b/webapp/packages/core-blocks/src/Table/TableSelect.tsx @@ -23,8 +23,8 @@ interface Props { const styles = css` Checkbox { - margin-left: -6px; - margin-right: -6px; + margin-left: -10px; + margin-right: -10px; } `; diff --git a/webapp/packages/core-blocks/src/Tags/Tags.tsx b/webapp/packages/core-blocks/src/Tags/Tags.tsx index 667fdfc240..b4a6203b7b 100644 --- a/webapp/packages/core-blocks/src/Tags/Tags.tsx +++ b/webapp/packages/core-blocks/src/Tags/Tags.tsx @@ -20,7 +20,7 @@ const style = css` width: 100%; display: flex; flex-wrap: wrap; - gap: 16px; + gap: 8px; } `; diff --git a/webapp/packages/core-blocks/src/ToolsPanel/ToolsPanel.tsx b/webapp/packages/core-blocks/src/ToolsPanel/ToolsPanel.tsx index 32fa9e9bc0..6b7a3bf748 100644 --- a/webapp/packages/core-blocks/src/ToolsPanel/ToolsPanel.tsx +++ b/webapp/packages/core-blocks/src/ToolsPanel/ToolsPanel.tsx @@ -9,7 +9,7 @@ import styled, { css } from 'reshadow'; const styles = css` container { - height: 30px; + height: 32px; display: flex; flex-shrink: 0; } diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeStyles.ts b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeStyles.ts index 248367e3e0..47e19c08d1 100644 --- a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeStyles.ts +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeStyles.ts @@ -59,10 +59,6 @@ export const TREE_NODE_STYLES = css` margin-right: 0; margin-left: 4px; } - - & TreeNodeName { - margin-right: 4px; - } } } @@ -99,7 +95,6 @@ export const TREE_NODE_STYLES = css` padding-right: 0; display: flex; align-items: center; - margin-right: 4px; } TreeNodeFilter { @@ -147,18 +142,21 @@ export const TREE_NODE_STYLES = css` } node TreeNodeControl[big] { - height: 32px; - padding: 0 8px; + height: 46px; + padding: 2 16px; + & TreeNodeSelect { + margin: 3px; + } & TreeNodeName { margin: 0; - padding-right: 4px; - padding-left: 4px; + padding-right: 16px; + padding-left: 16px; } & TreeNodeIcon, & TreeNodeExpand { - width: 16px; - height: 16px; + width: 24px; + height: 24px; } & TreeNodeExpand [|size='small'] { @@ -170,16 +168,12 @@ export const TREE_NODE_STYLES = css` } & > * { - margin-right: 4px; - margin-left: 4px; - } - - & TreeNodeSelect { - margin: 0; + margin-right: 11px; + margin-left: 11px; } } node TreeNodeControl[big] + TreeNodeNested { - padding-left: 16px; + padding-left: 46px; } `; diff --git a/webapp/packages/core-blocks/src/index.ts b/webapp/packages/core-blocks/src/index.ts index ad7a892281..371165db83 100644 --- a/webapp/packages/core-blocks/src/index.ts +++ b/webapp/packages/core-blocks/src/index.ts @@ -23,23 +23,15 @@ export * from './localization/Translate'; export * from './localization/useTranslate'; export * from './ConnectionImageWithMask/ConnectionImageWithMask'; -export { default as ConnectionImageWithMaskSvgStyles } from './ConnectionImageWithMask/ConnectionImageWithMaskSvg.m.css'; export * from './Menu/ACTION_ICON_BUTTON_STYLES'; export * from './Menu/Menu'; -export { default as MenuStyles } from './Menu/Menu.m.css'; export * from './Menu/MenuBarSmallItem'; export * from './Menu/MenuEmptyItem'; export * from './Menu/MenuItem'; -export { default as MenuItemStyles } from './Menu/MenuItem.m.css'; -export * from './Menu/MenuItemCheckbox'; export * from './Menu/MenuItemElement'; -export { default as MenuItemElementStyles } from './Menu/MenuItemElement.m.css'; -export * from './Menu/MenuItemRadio'; export * from './Menu/MenuPanel'; -export { default as MenuPanelStyles } from './Menu/MenuPanel.m.css'; -export * from './Menu/MenuSeparator'; -export { default as MenuSeparatorStyles } from './Menu/MenuSeparator.m.css'; +export * from './Menu/menuPanelStyles'; export * from './Menu/MenuStateContext'; export * from './Menu/useMouseContextMenu'; @@ -164,8 +156,6 @@ export * from './ExceptionMessage'; export * from './getComputed'; export * from './IconButton'; export * from './IconOrImage'; -export * from './s'; -export * from './SContext'; export * from './StaticImage'; export * from './TextPlaceholder'; export * from './TimerIcon'; @@ -187,7 +177,6 @@ export * from './useObjectRef'; export * from './useObservableRef'; export * from './usePermission'; export * from './usePromiseState'; -export * from './useS'; export * from './useStateDelay'; export * from './useErrorDetails'; export * from './useActivationDelay'; diff --git a/webapp/packages/core-blocks/src/layout/AppLogo.tsx b/webapp/packages/core-blocks/src/layout/AppLogo.tsx index 2ac4834d1e..693c43180a 100644 --- a/webapp/packages/core-blocks/src/layout/AppLogo.tsx +++ b/webapp/packages/core-blocks/src/layout/AppLogo.tsx @@ -14,13 +14,13 @@ const styles = css` height: 100%; display: flex; align-items: center; - padding: 0 8px; + padding: 0 14px; cursor: pointer; } IconOrImage { - height: 24px; - width: 120px; + height: 32px; + width: 154px; &[|small] { display: none; } diff --git a/webapp/packages/core-blocks/src/layout/TopAppBar.tsx b/webapp/packages/core-blocks/src/layout/TopAppBar.tsx index 7d669d9194..9bc131a8ea 100644 --- a/webapp/packages/core-blocks/src/layout/TopAppBar.tsx +++ b/webapp/packages/core-blocks/src/layout/TopAppBar.tsx @@ -12,7 +12,7 @@ export const topAppBarStyles = css` composes: theme-text-on-primary theme-typography--body2 from global; display: flex; align-items: center; - height: 32px; + height: 48px; padding: 0 8px; background-color: #2a7cb4; z-index: 1; diff --git a/webapp/packages/core-blocks/src/s.ts b/webapp/packages/core-blocks/src/s.ts deleted file mode 100644 index 0f9471c711..0000000000 --- a/webapp/packages/core-blocks/src/s.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2023 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import { type ClassValue, clsx } from '@cloudbeaver/core-utils'; - -export function s>(styles: T, options?: Partial>, ...inputs: ClassValue[]): string { - return clsx(...Object.entries(options ?? {}).map(([key, active]) => active && styles[key]), ...inputs); -} diff --git a/webapp/packages/core-blocks/src/useS.ts b/webapp/packages/core-blocks/src/useS.ts deleted file mode 100644 index 94b044d739..0000000000 --- a/webapp/packages/core-blocks/src/useS.ts +++ /dev/null @@ -1,108 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2023 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import { useContext, useMemo, useRef, useState } from 'react'; - -import { useService } from '@cloudbeaver/core-di'; -import { BaseStyles, ComponentStyle, Style, ThemeService } from '@cloudbeaver/core-theming'; - -import { SContextReact } from './SContext'; -import { useExecutor } from './useExecutor'; - -type Intersect = (T extends any ? (x: T) => 0 : never) extends (x: infer R) => 0 - ? R extends Record - ? BaseStyles - : never - : never; - -type ExtractStyles = Intersect< - T extends (infer U)[] - ? U extends BaseStyles - ? U - : U extends (theme: string) => Promise - ? A extends BaseStyles - ? A - : never - : never - : never ->; - -/** - * Changes styles depending on theme - * - * @param componentStyles styles array - */ -export function useS(...componentStyles: [...T]): ExtractStyles { - // todo do you understand that we store ALL STYLES in each component that uses this hook? - - const context = useContext(SContextReact); - const stylesRef = useRef([]); - const [patch, forceUpdate] = useState(0); - const loadedStyles = useRef([]); - const themeService = useService(ThemeService); - const [currentThemeId, setCurrentThemeId] = useState(() => themeService.currentThemeId); - const lastThemeRef = useRef(currentThemeId); - const filteredStyles = themeService.mapStyles(componentStyles.flat(Infinity).filter(Boolean) as Style[], context); - const trackTheme = filteredStyles.some(style => typeof style === 'function'); - - useExecutor({ - executor: themeService.onChange, - handlers: [ - function updateThemeId(theme) { - if (currentThemeId !== themeService.currentThemeId && trackTheme) { - setCurrentThemeId(theme.id); - } - }, - ], - }); - - let changed = lastThemeRef.current !== currentThemeId || filteredStyles.length !== stylesRef.current.length; - for (let i = 0; !changed && i < filteredStyles.length; i++) { - changed = stylesRef.current[i] !== filteredStyles[i]; - } - - if (changed) { - stylesRef.current = filteredStyles; - lastThemeRef.current = currentThemeId; - const staticStyles: BaseStyles[] = []; - const themedStyles: Array> = []; - - for (const style of filteredStyles) { - const data = typeof style === 'object' ? style : style(currentThemeId); - - if (data instanceof Promise) { - themedStyles.push(data); - } else { - staticStyles.push(data); - } - } - loadedStyles.current = staticStyles.flat(Infinity); - - if (themedStyles.length > 0) { - Promise.all(themedStyles).then(styles => { - loadedStyles.current = [staticStyles, styles].flat(Infinity).filter(Boolean) as BaseStyles[]; - forceUpdate(patch + 1); - }); - } - } - - const styles = useMemo(() => combineStyles(loadedStyles.current), [patch, loadedStyles.current]); - - return styles as ExtractStyles; // todo this method is called in each rerender -} - -export function combineStyles(styles: BaseStyles[]): BaseStyles { - const combined: BaseStyles = {}; - - for (const style of styles) { - for (const [key, value] of Object.entries(style)) { - combined[key] = [combined[key] || '', value].join(' ').trim(); - } - } - - return combined; -} diff --git a/webapp/packages/core-blocks/src/useStyles.ts b/webapp/packages/core-blocks/src/useStyles.ts index 78cd5dc26a..d32fafb864 100644 --- a/webapp/packages/core-blocks/src/useStyles.ts +++ b/webapp/packages/core-blocks/src/useStyles.ts @@ -10,6 +10,7 @@ import { create } from 'reshadow'; import { useService } from '@cloudbeaver/core-di'; import { BaseStyles, ComponentStyle, Style, ThemeService } from '@cloudbeaver/core-theming'; +import { flat } from '@cloudbeaver/core-utils'; import { useExecutor } from './useExecutor'; @@ -27,8 +28,7 @@ export function useStyles(...componentStyles: ComponentStyle[]): Record themeService.currentThemeId); const lastThemeRef = useRef(currentThemeId); - //@ts-ignore - const filteredStyles = componentStyles.flat(Infinity).filter(Boolean) as Style[]; + const filteredStyles = flat(componentStyles).filter(Boolean) as Style[]; const trackTheme = filteredStyles.some(style => typeof style === 'function'); useExecutor({ @@ -62,11 +62,11 @@ export function useStyles(...componentStyles: ComponentStyle[]): Record 0) { Promise.all(themedStyles).then(styles => { - loadedStyles.current = [staticStyles, styles].flat(Infinity).filter(Boolean) as BaseStyles[]; + loadedStyles.current = flat([staticStyles, flat(styles)]).filter(Boolean) as BaseStyles[]; forceUpdate(patch + 1); }); } @@ -78,6 +78,5 @@ export function useStyles(...componentStyles: ComponentStyle[]): Record { process.env.NODE_ENV = argv.mode; const devTool = 'source-map' in env && 'source-map'; @@ -52,7 +49,7 @@ module.exports = (env, argv) => { return loaders; } - function generateStyleLoaders(options = { hasModule: false, disable: false, pure: false }) { + function generateStyleLoaders(options = { hasModule: false, disable: false }) { const moduleScope = options.hasModule ? 'local' : 'global'; let modules = { mode: moduleScope, @@ -63,11 +60,7 @@ module.exports = (env, argv) => { modules = false; } - const postCssPlugins = [require('postcss-preset-env')({ stage: 0 })]; - - if (!options.pure) { - postCssPlugins.push(require('@reshadow/postcss')({ scopeBehaviour: moduleScope })); - } + const postCssPlugins = [require('postcss-preset-env')({ stage: 0 }), require('@reshadow/postcss')({ scopeBehaviour: moduleScope })]; return [ ...getBaseStyleLoaders(), @@ -75,27 +68,26 @@ module.exports = (env, argv) => { loader: 'css-loader', options: { modules: modules, - sourceMap: devMode, + sourceMap: true, }, }, + { loader: 'postcss-loader', options: { - sourceMap: devMode, postcssOptions: { plugins: postCssPlugins, - sourceMap: devMode, + sourceMap: true, }, }, }, { loader: 'sass-loader', options: { - sourceMap: devMode, + sourceMap: true, sassOptions: { implementation: require('sass'), includePaths: nodeModules, - quietDeps: true, }, }, }, @@ -105,8 +97,7 @@ module.exports = (env, argv) => { var babelLoader = { loader: require.resolve('babel-loader'), options: { - root: __dirname, - cacheDirectory: true, + configFile: join(__dirname, 'babel.config.js'), }, }; @@ -208,16 +199,11 @@ module.exports = (env, argv) => { }, { test: /\.(css|s[ac]ss)$/, - exclude: /node_modules/, oneOf: [ { test: /\.module\.(css|s[ac]ss)$/, use: generateStyleLoaders({ hasModule: true }), }, - { - test: /\.m\.(css|s[ac]ss)$/, - use: generateStyleLoaders({ hasModule: true, pure: true }), - }, { include: /node_modules/, use: [...getBaseStyleLoaders(), 'css-loader', 'sass-loader'], diff --git a/webapp/packages/core-cli/configs/webpack.product.dev.config.js b/webapp/packages/core-cli/configs/webpack.product.dev.config.js index 5746287eff..f1e898a033 100644 --- a/webapp/packages/core-cli/configs/webpack.product.dev.config.js +++ b/webapp/packages/core-cli/configs/webpack.product.dev.config.js @@ -43,8 +43,7 @@ module.exports = (env, argv) => { sso, }, optimization: { - minimize: false, - moduleIds: 'named', + minimize: true, }, devServer: { allowedHosts: 'all', @@ -72,7 +71,10 @@ module.exports = (env, argv) => { httpProxy.createProxyServer({ target:`http://127.0.0.1:${port}` }).listen(8080); }, }, - devtool: 'source-map', + devtool: 'eval-source-map', + // optimization: { + // moduleIds: 'named', + // }, plugins: [ new CopyWebpackPlugin({ patterns: getAssets(package, ''), diff --git a/webapp/packages/core-cli/package.json b/webapp/packages/core-cli/package.json index b357005498..4af6e53f6b 100644 --- a/webapp/packages/core-cli/package.json +++ b/webapp/packages/core-cli/package.json @@ -7,7 +7,6 @@ "files": [ "/package.json", "/tsconfig.json", - "/global.d.ts", "/src", "/configs", "/bin", @@ -72,6 +71,8 @@ }, "peerDependencies": { "@types/jest": "~29.x.x", + "@types/react": "~18.x.x", + "@types/react-dom": "~18.x.x", "babel-jest": "~29.x.x", "jest": "~29.x.x", "jest-environment-jsdom": "~29.x.x" diff --git a/webapp/packages/core-dialogs/src/CommonDialog/CommonDialog/styles.ts b/webapp/packages/core-dialogs/src/CommonDialog/CommonDialog/styles.ts index bed5c92ba7..4a6f3cc023 100644 --- a/webapp/packages/core-dialogs/src/CommonDialog/CommonDialog/styles.ts +++ b/webapp/packages/core-dialogs/src/CommonDialog/CommonDialog/styles.ts @@ -91,7 +91,7 @@ export const commonDialogBaseStyle = [ dialog-body, footer { flex-shrink: 0; - padding: 16px; + padding: 24px; &[|no-padding] { padding: 0px; diff --git a/webapp/packages/core-dialogs/src/CommonDialog/styles.ts b/webapp/packages/core-dialogs/src/CommonDialog/styles.ts index 57fdfaf383..4e02b53727 100644 --- a/webapp/packages/core-dialogs/src/CommonDialog/styles.ts +++ b/webapp/packages/core-dialogs/src/CommonDialog/styles.ts @@ -26,7 +26,7 @@ export const dialogStyles = css` inner-box { display: flex; margin: auto; - padding: 16px; + padding: 24px; flex-direction: column; align-items: center; diff --git a/webapp/packages/core-notifications/src/NotificationsItem/ErrorDetailsDialog/styles.ts b/webapp/packages/core-notifications/src/NotificationsItem/ErrorDetailsDialog/styles.ts index 7224f87b35..6c3815b8dd 100644 --- a/webapp/packages/core-notifications/src/NotificationsItem/ErrorDetailsDialog/styles.ts +++ b/webapp/packages/core-notifications/src/NotificationsItem/ErrorDetailsDialog/styles.ts @@ -29,6 +29,6 @@ export const styles = css` CommonDialogFooter { align-items: center; justify-content: flex-end; - gap: 16px; + gap: 24px; } `; diff --git a/webapp/packages/core-theming/src/ComponentStyle.ts b/webapp/packages/core-theming/src/ComponentStyle.ts index bd2dee9ddc..7b190dae06 100644 --- a/webapp/packages/core-theming/src/ComponentStyle.ts +++ b/webapp/packages/core-theming/src/ComponentStyle.ts @@ -7,10 +7,8 @@ */ import type { ClassCollection } from './themeUtils'; -export type BaseStyles = Record> = ClassCollection; -export type ThemeSelector = Record> = ( - theme: string, -) => Promise | BaseStyles[]>; -export type Style = Record> = BaseStyles | ThemeSelector; -export type DynamicStyle = Record> = Style | boolean | undefined; -export type ComponentStyle = Record> = DynamicStyle | ComponentStyle[]; +export type BaseStyles = ClassCollection; +export type ThemeSelector = (theme: string) => Promise; +export type Style = BaseStyles | ThemeSelector; +export type DynamicStyle = Style | boolean | undefined; +export type ComponentStyle = DynamicStyle | DynamicStyle[] | DynamicStyle[][]; diff --git a/webapp/packages/core-theming/src/ThemeService.ts b/webapp/packages/core-theming/src/ThemeService.ts index fbf47723d4..f2164fa6fc 100644 --- a/webapp/packages/core-theming/src/ThemeService.ts +++ b/webapp/packages/core-theming/src/ThemeService.ts @@ -13,7 +13,6 @@ import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor'; import { ServerConfigResource } from '@cloudbeaver/core-root'; import { SettingsService } from '@cloudbeaver/core-settings'; -import type { Style } from './ComponentStyle'; import './styles/main/base.pure.css'; import './styles/main/color.pure.scss'; import './styles/main/elevation.pure.scss'; @@ -38,11 +37,6 @@ interface ISettings { currentThemeId: string; } -export interface IStyleRegistry { - mode: 'replace' | 'append'; - styles: Style[]; -} - @injectable() export class ThemeService extends Bootstrap { get themes(): ITheme[] { @@ -73,7 +67,6 @@ export class ThemeService extends Bootstrap { readonly onChange: ISyncExecutor; - private readonly stylesRegistry: Map = new Map(); private readonly themeMap: Map = new Map(); private readonly settings: ISettings; @@ -102,37 +95,6 @@ export class ThemeService extends Bootstrap { this.loadAllThemes(); } - addStyleRegistry>(style: Style, mode: 'replace' | 'append', styles: Style[]): void { - if (!this.stylesRegistry.has(style)) { - this.stylesRegistry.set(style, []); - } - - this.stylesRegistry.get(style)!.push({ mode, styles }); - } - - mapStyles>(styles: Style[], context?: Map): Style[] { - return styles - .map(style => { - const registries = this.stylesRegistry.get(style) ?? context?.get(style); - - if (!registries) { - return [style]; - } - - return registries.reduce( - (acc, registry) => { - if (registry.mode === 'replace') { - acc = acc.filter(s => s !== style); - } - - return [...acc, ...this.mapStyles(registry.styles, context)] as Style[]; - }, - [style] as Style[], - ); - }) - .flat(); - } - async load(): Promise { await this.serverConfigResource.load(); this.setCurrentThemeId(this.defaultThemeId); // set default app theme diff --git a/webapp/packages/core-theming/src/styles/_button.scss b/webapp/packages/core-theming/src/styles/_button.scss index 23fb1b9663..9720df14e0 100644 --- a/webapp/packages/core-theming/src/styles/_button.scss +++ b/webapp/packages/core-theming/src/styles/_button.scss @@ -8,12 +8,10 @@ @mixin button-core-styles() { $mdc-button-disabled-container-fill-color: #cccccc; - $mdc-button-density-scale: -3; - $mdc-density-default-scale: -3; + $mdc-button-density-scale: -2; $query: mdc-feature-all(); @include mdc-button-core-styles; @include mdc-button-theme-baseline; - @include mdc-button-density(-3); .theme-button { @extend .mdc-button; @@ -86,4 +84,4 @@ @include mdc-states($color: on-secondary, $query: $query, $ripple-target: $mdc-button-ripple-target); } } -} +} \ No newline at end of file diff --git a/webapp/packages/core-theming/src/styles/_checkbox.scss b/webapp/packages/core-theming/src/styles/_checkbox.scss index 3b020dee22..7593c51b61 100644 --- a/webapp/packages/core-theming/src/styles/_checkbox.scss +++ b/webapp/packages/core-theming/src/styles/_checkbox.scss @@ -6,14 +6,11 @@ * you may not use this file except in compliance with the License. */ -@import '@material/checkbox/mixins'; +@import "@material/checkbox/mixins"; $mdc-checkbox-icon-size: 16px; -$mdc-checkbox-density-scale: -3; -$mdc-density-default-scale: -3; @mixin checkbox-core-styles($query: mdc-feature-all()) { @include mdc-checkbox-core-styles($query); - @include mdc-checkbox-density(-3); .theme-checkbox { @extend .mdc-checkbox; @@ -51,14 +48,24 @@ $mdc-density-default-scale: -3; $mdc-checkbox-mark-color: $mdc-theme-on-primary; @include mdc-checkbox-ink-color($mdc-checkbox-mark-color, $query); @include mdc-checkbox-disabled-ink-color(rgba($mdc-checkbox-mark-color, 0.5), $query); - @include mdc-checkbox-container-colors($mdc-checkbox-border-color, transparent, $mdc-theme-primary, $mdc-theme-primary); + @include mdc-checkbox-container-colors( + $mdc-checkbox-border-color, + transparent, + $mdc-theme-primary, + $mdc-theme-primary + ); } .theme-checkbox_surface { $mdc-checkbox-mark-color: $mdc-theme-primary; @include mdc-checkbox-ink-color($mdc-checkbox-mark-color, $query); @include mdc-checkbox-disabled-ink-color(rgba($mdc-checkbox-mark-color, 0.5), $query); - @include mdc-checkbox-container-colors($mdc-theme-surface, transparent, $mdc-theme-surface, $mdc-theme-surface); + @include mdc-checkbox-container-colors( + $mdc-theme-surface, + transparent, + $mdc-theme-surface, + $mdc-theme-surface + ); } .theme-checkbox_small { diff --git a/webapp/packages/core-theming/src/styles/_radio.scss b/webapp/packages/core-theming/src/styles/_radio.scss index 1a7cb840c8..6b9e743d0a 100644 --- a/webapp/packages/core-theming/src/styles/_radio.scss +++ b/webapp/packages/core-theming/src/styles/_radio.scss @@ -6,15 +6,10 @@ * you may not use this file except in compliance with the License. */ -@import '@material/radio/mixins'; -$mdc-radio-density-scale: -3; -$mdc-density-default-scale: -3; -$mdc-radio-touch-area: 32px !default; -$mdc-radio-ui-size: 16px !default; +@import "@material/radio/mixins"; @mixin radio-core-styles($query: mdc-feature-all()) { @include mdc-radio-core-styles; - @include mdc-radio-density(-3); .theme-radio { @extend .mdc-radio; @@ -69,4 +64,4 @@ $mdc-radio-ui-size: 16px !default; .theme-radio_no-ripple { @include mdc-radio-ripple-size(0); } -} +} \ No newline at end of file diff --git a/webapp/packages/core-theming/src/styles/_switch.scss b/webapp/packages/core-theming/src/styles/_switch.scss index f4d729dcb3..0ce1270486 100644 --- a/webapp/packages/core-theming/src/styles/_switch.scss +++ b/webapp/packages/core-theming/src/styles/_switch.scss @@ -7,12 +7,10 @@ */ @import '@material/switch/mixins'; -$mdc-switch-density-scale: -3; -$mdc-density-default-scale: -3; @mixin switch-core-styles($query: mdc-feature-all()) { @include mdc-switch-core-styles($query); - + .theme-switch { @extend .mdc-switch; } @@ -43,8 +41,7 @@ $mdc-density-default-scale: -3; @include switch-core-styles-dense($query); } - .theme-switch_dense .theme-switch_primary, - .theme-switch_primary { + .theme-switch_dense .theme-switch_primary, .theme-switch_primary { $mdc-switch-baseline-theme-color: primary; @include mdc-switch-toggled-on-track-color($mdc-switch-baseline-theme-color, $query); @@ -74,7 +71,8 @@ $mdc-density-default-scale: -3; $mdc-switch-thumb-offset: 2px !global; - $mdc-switch-thumb-active-margin: $mdc-switch-track-width - $mdc-switch-thumb-diameter + $mdc-switch-thumb-offset * 2 !global; + $mdc-switch-thumb-active-margin: + $mdc-switch-track-width - $mdc-switch-thumb-diameter + $mdc-switch-thumb-offset * 2 !global; @include mdc-switch-core-styles($query); -} +} \ No newline at end of file diff --git a/webapp/packages/core-theming/src/styles/theme-dark.module.scss b/webapp/packages/core-theming/src/styles/theme-dark.module.scss index 5a3604571c..63065ed8af 100644 --- a/webapp/packages/core-theming/src/styles/theme-dark.module.scss +++ b/webapp/packages/core-theming/src/styles/theme-dark.module.scss @@ -20,5 +20,5 @@ @include form-controls; @include link; @include placeholder; -@include delimiter($mdc-theme-background); +@include delimiter($mdc-theme-secondary); @include branding-overflow; diff --git a/webapp/packages/core-theming/src/styles/theme-light.module.scss b/webapp/packages/core-theming/src/styles/theme-light.module.scss index dd99c2d0af..48c3b0546e 100644 --- a/webapp/packages/core-theming/src/styles/theme-light.module.scss +++ b/webapp/packages/core-theming/src/styles/theme-light.module.scss @@ -20,5 +20,5 @@ @include form-controls; @include link; @include placeholder; -@include delimiter($mdc-theme-background); +@include delimiter($mdc-theme-secondary); @include branding-overflow; diff --git a/webapp/packages/core-theming/src/themeUtils.ts b/webapp/packages/core-theming/src/themeUtils.ts index 0ae949cd2a..47e71d9a10 100644 --- a/webapp/packages/core-theming/src/themeUtils.ts +++ b/webapp/packages/core-theming/src/themeUtils.ts @@ -6,9 +6,9 @@ * you may not use this file except in compliance with the License. */ -export type ClassCollection = Record> = { - [Key in keyof T]: string; -}; +export interface ClassCollection { + [key: string]: any; +} export class Composes { composes: ClassCollection; diff --git a/webapp/packages/core-ui/src/ContextMenu/ContextMenu.tsx b/webapp/packages/core-ui/src/ContextMenu/ContextMenu.tsx index 37ee91209f..22bcc2ea3b 100644 --- a/webapp/packages/core-ui/src/ContextMenu/ContextMenu.tsx +++ b/webapp/packages/core-ui/src/ContextMenu/ContextMenu.tsx @@ -8,8 +8,20 @@ import { observer } from 'mobx-react-lite'; import { ButtonHTMLAttributes, forwardRef, useRef, useState } from 'react'; import type { MenuInitialState } from 'reakit/Menu'; +import styled from 'reshadow'; -import { getComputed, IMenuState, IMouseContextMenu, Menu, useAutoLoad, useObjectRef, useTranslate } from '@cloudbeaver/core-blocks'; +import { + getComputed, + IMenuState, + IMouseContextMenu, + Menu, + menuPanelStyles, + useAutoLoad, + useObjectRef, + useStyles, + useTranslate, +} from '@cloudbeaver/core-blocks'; +import type { ComponentStyle } from '@cloudbeaver/core-theming'; import { IMenuData, MenuActionItem } from '@cloudbeaver/core-view'; import { MenuItemRenderer } from './MenuItemRenderer'; @@ -21,9 +33,10 @@ interface IMenuProps extends React.PropsWithChildren { type ContextMenuRenderingChildren = (props: IMenuProps) => React.ReactNode | React.ReactElement; -interface IContextMenuProps extends Omit, 'children'> { +interface IContextMenuProps extends Omit, 'style' | 'children'> { mouseContextMenu?: IMouseContextMenu; menu: IMenuData; + style?: ComponentStyle; disclosure?: boolean; placement?: MenuInitialState['placement']; modal?: boolean; @@ -35,7 +48,7 @@ interface IContextMenuProps extends Omit, 'children'> export const ContextMenu = observer( forwardRef(function ContextMenu( - { mouseContextMenu, menu: menuData, disclosure, children, placement, visible, onVisibleSwitch, modal, rtl, ...props }, + { mouseContextMenu, menu: menuData, disclosure, children, style, placement, visible, onVisibleSwitch, modal, rtl, ...props }, ref, ) { const translate = useTranslate(); @@ -48,6 +61,7 @@ export const ContextMenu = observer( const lazy = getComputed(() => !menuData.available || hidden); const menu = useRef(); + const styles = useStyles(menuPanelStyles, style); useAutoLoad(menuData.loaders, !lazy, menuVisible); @@ -78,7 +92,7 @@ export const ContextMenu = observer( const renderingChildren: React.ReactNode = typeof children === 'function' ? children({ loading, disabled }) : children; - return ( + return styled(styles)( ( menuData.items.map( item => menu.current && ( - + ), ) } @@ -99,12 +122,13 @@ export const ContextMenu = observer( placement={placement} disabled={disabled} disclosure={disclosure} + style={style} getHasBindings={handlers.hasBindings} onVisibleSwitch={handlers.handleVisibleSwitch} {...props} > {renderingChildren} - + , ); }), ); diff --git a/webapp/packages/core-ui/src/ContextMenu/IContextMenuItemProps.ts b/webapp/packages/core-ui/src/ContextMenu/IContextMenuItemProps.ts index 446be6196d..961876f42b 100644 --- a/webapp/packages/core-ui/src/ContextMenu/IContextMenuItemProps.ts +++ b/webapp/packages/core-ui/src/ContextMenu/IContextMenuItemProps.ts @@ -5,10 +5,15 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import type { MenuStateReturn } from 'reakit/ts'; + +import type { ComponentStyle } from '@cloudbeaver/core-theming'; import type { IMenuData, IMenuItem } from '@cloudbeaver/core-view'; export interface IContextMenuItemProps { item: IMenuItem; + menu: MenuStateReturn; menuData: IMenuData; + style?: ComponentStyle; onClick: () => void; } diff --git a/webapp/packages/core-ui/src/ContextMenu/MenuActionElement.tsx b/webapp/packages/core-ui/src/ContextMenu/MenuActionElement.tsx index bdcdd0dcfb..4f2aab420f 100644 --- a/webapp/packages/core-ui/src/ContextMenu/MenuActionElement.tsx +++ b/webapp/packages/core-ui/src/ContextMenu/MenuActionElement.tsx @@ -7,8 +7,10 @@ */ import { observer } from 'mobx-react-lite'; import React from 'react'; +import { MenuItem, MenuItemCheckbox, MenuItemRadio } from 'reakit/Menu'; +import styled, { use } from 'reshadow'; -import { Checkbox, MenuItem, MenuItemCheckbox, MenuItemElement, MenuItemRadio, Radio } from '@cloudbeaver/core-blocks'; +import { Checkbox, MenuItemElement, menuPanelStyles, Radio, useStyles } from '@cloudbeaver/core-blocks'; import type { IMenuActionItem } from '@cloudbeaver/core-view'; import type { IContextMenuItemProps } from './IContextMenuItemProps'; @@ -17,7 +19,8 @@ interface IMenuActionElementProps extends IContextMenuItemProps { item: IMenuActionItem; } -export const MenuActionElement = observer(function MenuActionElement({ item, onClick }) { +export const MenuActionElement = observer(function MenuActionElement({ item, menu, style, onClick }) { + const styles = useStyles(menuPanelStyles, style); const actionInfo = item.action.actionInfo; const loading = item.action.isLoading(); @@ -28,9 +31,10 @@ export const MenuActionElement = observer(function Menu if (actionInfo.type === 'select') { const checked = item.action.isChecked(); - return ( + return styled(styles)( + , ); } if (actionInfo.type === 'checkbox') { const checked = item.action.isChecked(); - return ( + return styled(styles)( + , ); } - return ( - , ); }); diff --git a/webapp/packages/core-ui/src/ContextMenu/MenuBar/MENU_BAR_DEFAULT_STYLES.ts b/webapp/packages/core-ui/src/ContextMenu/MenuBar/MENU_BAR_DEFAULT_STYLES.ts new file mode 100644 index 0000000000..882f28b156 --- /dev/null +++ b/webapp/packages/core-ui/src/ContextMenu/MenuBar/MENU_BAR_DEFAULT_STYLES.ts @@ -0,0 +1,70 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { css } from 'reshadow'; + +export const MENU_BAR_DEFAULT_STYLES = css` + menu-bar { + composes: theme-background-secondary theme-text-on-secondary theme-border-color-background theme-typography--body2 from global; + height: 48px; + display: flex; + } + + menu-bar-item { + composes: theme-ripple from global; + padding: 0 16px; + cursor: pointer; + background: transparent; + outline: none; + color: inherit; + + & menu-bar-item-box { + display: flex; + align-items: center; + } + + &[use|hidden] { + display: none; + } + + & menu-bar-item-icon { + display: flex; + width: 24px; + } + + & Loader, + & IconOrImage { + width: 24px; + } + + & menu-bar-item-label { + display: block; + text-transform: uppercase; + font-weight: 700; + } + + & menu-bar-item-icon + menu-bar-item-label { + padding-left: 8px; + } + + & menu-bar-item-mark { + display: none; + } + } + + MenuSeparator { + composes: theme-border-color-background from global; + height: 100%; + margin: 0; + border: 1px solid !important; + + &:first-child, + &:last-child { + display: none; + } + } +`; diff --git a/webapp/packages/core-ui/src/ContextMenu/MenuBar/MENU_BAR_SMALL_STYLES.ts b/webapp/packages/core-ui/src/ContextMenu/MenuBar/MENU_BAR_SMALL_STYLES.ts new file mode 100644 index 0000000000..02883a757c --- /dev/null +++ b/webapp/packages/core-ui/src/ContextMenu/MenuBar/MENU_BAR_SMALL_STYLES.ts @@ -0,0 +1,31 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 DBeaver Corp and others + * + * Licensed under the Apache License, Version 2.0. + * you may not use this file except in compliance with the License. + */ +import { css } from 'reshadow'; + +export const MENU_BAR_SMALL_STYLES = css` + menu-bar-item { + padding: 0 12px; + + & menu-bar-item-icon { + display: flex; + width: 16px; + } + + & menu-bar-item-label { + font-size: 12px; + } + + & Loader, + & IconOrImage { + width: 16px; + } + } + menu-bar { + height: 32px; + } +`; diff --git a/webapp/packages/core-ui/src/ContextMenu/MenuBar/MenuBar.m.css b/webapp/packages/core-ui/src/ContextMenu/MenuBar/MenuBar.m.css deleted file mode 100644 index 9b4480dc7b..0000000000 --- a/webapp/packages/core-ui/src/ContextMenu/MenuBar/MenuBar.m.css +++ /dev/null @@ -1,19 +0,0 @@ -.menuBar { - height: 32px; - display: flex; - - & > .menuSeparator { - height: 100%; - margin: 0; - border: 1px solid !important; - - &:first-child, - &:last-child { - display: none; - } - } -} - -.floating.menuBar { - height: 28px; -} diff --git a/webapp/packages/core-ui/src/ContextMenu/MenuBar/MenuBar.tsx b/webapp/packages/core-ui/src/ContextMenu/MenuBar/MenuBar.tsx index 3101d8caa0..739be1e7c6 100644 --- a/webapp/packages/core-ui/src/ContextMenu/MenuBar/MenuBar.tsx +++ b/webapp/packages/core-ui/src/ContextMenu/MenuBar/MenuBar.tsx @@ -7,9 +7,11 @@ */ import { observer } from 'mobx-react-lite'; import { forwardRef, useCallback } from 'react'; -import type { MenuInitialState } from 'reakit'; +import { MenuInitialState, MenuSeparator } from 'reakit'; +import styled, { use } from 'reshadow'; -import { getComputed, MenuSeparator, MenuSeparatorStyles, s, SContext, StyleRegistry, useAutoLoad, useS } from '@cloudbeaver/core-blocks'; +import { getComputed, Loader, useAutoLoad, useStyles } from '@cloudbeaver/core-blocks'; +import type { ComponentStyle } from '@cloudbeaver/core-theming'; import { DATA_CONTEXT_MENU_NESTED, DATA_CONTEXT_SUBMENU_ITEM, @@ -24,32 +26,22 @@ import { } from '@cloudbeaver/core-view'; import { ContextMenu } from '../ContextMenu'; -import style from './MenuBar.m.css'; import { MenuBarItem } from './MenuBarItem'; interface INestedMenuSettings extends MenuInitialState { onVisibleSwitch?: (visible: boolean) => void; } -interface IMenuBarProps extends React.HTMLAttributes { +interface IMenuBarProps extends Omit, 'style'> { menu: IMenuData; nestedMenuSettings?: INestedMenuSettings; + style?: ComponentStyle; rtl?: boolean; } -const registry: StyleRegistry = [ - [ - MenuSeparatorStyles, - { - mode: 'append', - styles: [style], - }, - ], -]; - export const MenuBar = observer( - forwardRef(function MenuBar({ menu, nestedMenuSettings, rtl, className, ...props }, ref) { - const styles = useS(style); + forwardRef(function MenuBar({ menu, nestedMenuSettings, style, rtl, ...props }, ref) { + const styles = useStyles(style); const items = menu.items; useAutoLoad(menu.loaders); @@ -57,14 +49,12 @@ export const MenuBar = observer( return null; } - return ( - -
- {items.map(item => ( - - ))} -
-
+ return styled(styles)( + + {items.map(item => ( + + ))} + , ); }), ); @@ -75,9 +65,12 @@ interface IMenuBarElementProps { nestedMenuSettings?: INestedMenuSettings; className?: string; rtl?: boolean; + style?: ComponentStyle; } -const MenuBarElement = observer(function MenuBarElement({ item, menuData, nestedMenuSettings, className, rtl }) { +const MenuBarElement = observer(function MenuBarElement({ item, menuData, nestedMenuSettings, className, rtl, style }) { + const styles = useStyles(style); + const onClick = useCallback(() => { item.events?.onSelect?.(); }, [item]); @@ -87,30 +80,33 @@ const MenuBarElement = observer(function MenuBarElement({ } if (item instanceof MenuSubMenuItem) { - return ; + return styled(styles)( + , + ); } if (item instanceof MenuSeparatorItem) { - return ; + return styled(styles)(); } if (item instanceof MenuActionItem) { - return ; + return styled(styles)(); } if (item instanceof MenuBaseItem) { - return ( + return styled(styles)(