diff --git a/package.json b/package.json index 138d4d0f6b..6ea711e240 100644 --- a/package.json +++ b/package.json @@ -312,7 +312,6 @@ "jest": "^26.0.1", "jest-mock-extended": "^1.0.10", "make-plural": "^6.2.1", - "material-design-icons": "^3.0.1", "mini-css-extract-plugin": "^0.9.0", "mobx-react": "^6.2.2", "moment": "^2.26.0", diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index 4aecc26884..1f989f0c4b 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -57,7 +57,7 @@ export class Nodes extends React.Component { max={cores} value={usage} tooltip={{ - position: TooltipPosition.BOTTOM, + preferredPositions: TooltipPosition.BOTTOM, children: _i18n._(t`CPU:`) + ` ${Math.ceil(usage * 100) / cores}\%, ` + _i18n._(t`cores:`) + ` ${cores}` }} /> @@ -74,7 +74,7 @@ export class Nodes extends React.Component { max={capacity} value={usage} tooltip={{ - position: TooltipPosition.BOTTOM, + preferredPositions: TooltipPosition.BOTTOM, children: _i18n._(t`Memory:`) + ` ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}` }} /> @@ -91,7 +91,7 @@ export class Nodes extends React.Component { max={capacity} value={usage} tooltip={{ - position: TooltipPosition.BOTTOM, + preferredPositions: TooltipPosition.BOTTOM, children: _i18n._(t`Disk:`) + ` ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}` }} /> diff --git a/src/renderer/components/+support/support.scss b/src/renderer/components/+support/support.scss index 473e638558..3db1943280 100644 --- a/src/renderer/components/+support/support.scss +++ b/src/renderer/components/+support/support.scss @@ -1,67 +1,3 @@ +// TODO: figure out how to consume extra styles from extensions .Support { - position: fixed!important; // Allows to cover ClustersMenu - z-index: 1; - - .WizardLayout { - grid-template-columns: unset; - grid-template-rows: 76px 1fr; - padding: 0; - - .content-col { - padding: $padding * 8 0; - background-color: $clusterSettingsBackground; - - h2 { - margin-bottom: $margin * 2; - - &:not(:first-child) { - margin-top: $margin * 3; - } - } - - .SubTitle { - text-transform: none; - margin: 0!important; - } - - .repos { - position: relative; - - .Badge { - display: flex; - margin: 0; - margin-bottom: 1px; - padding: $padding $padding * 2; - } - } - - .hint { - margin-top: -$margin; - } - } - - span.supportLink { - cursor: pointer; - color: $primary; - text-decoration: underline; - position: relative; - } - } - - .is-mac & { - .WizardLayout .head-col { - padding-top: 32px; - overflow: hidden; - - .Icon { - margin-top: -$margin * 2; - } - } - } - - .Select { - &__control { - box-shadow: 0 0 0 1px $borderFaintColor; - } - } } \ No newline at end of file diff --git a/src/renderer/components/+support/support.tsx b/src/renderer/components/+support/support.tsx index 3d7137fd85..1859173b43 100644 --- a/src/renderer/components/+support/support.tsx +++ b/src/renderer/components/+support/support.tsx @@ -1,51 +1,28 @@ import "./support.scss" + import React from "react" import { observer } from "mobx-react" -import { Icon } from "../icon" -import { WizardLayout } from "../layout/wizard-layout" -import { history } from "../../navigation" import { Trans } from "@lingui/macro" -import { shell } from "electron" import { issuesTrackerUrl, slackUrl } from "../../../common/vars"; -import { t } from "@lingui/macro"; -import { _i18n } from "../../i18n"; +import { PageLayout } from "../layout/page-layout"; @observer export class Support extends React.Component { - - async componentDidMount() { - window.addEventListener('keydown', this.onEscapeKey); - } - - componentWillUnmount() { - window.removeEventListener('keydown', this.onEscapeKey); - } - - onEscapeKey = (evt: KeyboardEvent) => { - if (evt.code === "Escape") { - evt.stopPropagation(); - history.goBack(); - } - } - render() { - const header = ( - <> -

Support

- - - ); return ( -
- -

Community Slack Channel

-

{_i18n._(t`Ask a question, see what's being discussed, join the conversation`)} shell.openExternal(slackUrl) }>here

-

Report an Issue

-

{_i18n._(t`Review existing issues or open a new one`)} shell.openExternal(issuesTrackerUrl) }>here

-

Commercial Support

-

TBD

-
-
+ Support}> +

Community Slack Channel

+

+ Ask a question, see what's being discussed, join the conversation here{" "} +

+ +

Report an Issue

+

+ Review existing issues or open a new one here +

+ + {/*

Commercial Support

*/} +
); } } diff --git a/src/renderer/components/cluster-manager/bottom-bar.scss b/src/renderer/components/cluster-manager/bottom-bar.scss index 79f1f7e769..359c123836 100644 --- a/src/renderer/components/cluster-manager/bottom-bar.scss +++ b/src/renderer/components/cluster-manager/bottom-bar.scss @@ -10,9 +10,4 @@ --flex-gap: #{$spacing}; cursor: pointer; } - - #support { - --flex-gap: #{$spacing}; - cursor: pointer; - } } diff --git a/src/renderer/components/cluster-manager/bottom-bar.tsx b/src/renderer/components/cluster-manager/bottom-bar.tsx index db52f04856..2ceacb925b 100644 --- a/src/renderer/components/cluster-manager/bottom-bar.tsx +++ b/src/renderer/components/cluster-manager/bottom-bar.tsx @@ -1,10 +1,10 @@ import "./bottom-bar.scss" + import React from "react"; import { observer } from "mobx-react"; import { Icon } from "../icon"; import { WorkspaceMenu } from "../+workspaces/workspace-menu"; import { workspaceStore } from "../../../common/workspace-store"; - import { supportURL } from "../+support/support.route"; import { navigate } from "../../navigation"; @@ -19,13 +19,13 @@ export class BottomBar extends React.Component { {currentWorkspace.name} -
- navigate(supportURL())} - /> -
+ navigate(supportURL())} + /> ) } diff --git a/src/renderer/components/fonts.scss b/src/renderer/components/fonts.scss index 76f2199e0a..102f87d05e 100644 --- a/src/renderer/components/fonts.scss +++ b/src/renderer/components/fonts.scss @@ -1,7 +1,15 @@ // Custom fonts -@import "~material-design-icons/iconfont/material-icons.css"; @import "~typeface-roboto/index.css"; +// Material Design Icons, used primarily in icon.tsx +// Latest: https://github.com/google/material-design-icons/tree/master/font +@font-face { + font-family: "Material Icons"; + font-style: normal; + font-weight: 400; + src: url("../fonts/MaterialIcons-Regular.ttf") format("truetype"); +} + // Patched RobotoMono font with icons // RobotoMono Windows Compatible for using in terminal // https://github.com/ryanoasis/nerd-fonts/tree/master/patched-fonts/RobotoMono diff --git a/src/renderer/components/icon/support.svg b/src/renderer/components/icon/support.svg deleted file mode 100644 index e5e775c32e..0000000000 --- a/src/renderer/components/icon/support.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/renderer/components/layout/page-layout.scss b/src/renderer/components/layout/page-layout.scss new file mode 100644 index 0000000000..2616a922ab --- /dev/null +++ b/src/renderer/components/layout/page-layout.scss @@ -0,0 +1,55 @@ +.PageLayout { + $spacing: $padding * 2; + + position: relative; + height: 100%; + display: grid !important; + grid-template-rows: min-content 1fr; + + // global page, covers whole app screen + &.global { + position: fixed !important; // allow to cover ClustersMenu + z-index: 1; + } + + > .header { + position: sticky; + padding: $spacing; + background-color: $layoutTabsBackground; + + // add extra spacing for traffic-light top buttons (mac only) + .is-mac & { + padding-top: $spacing * 2; + } + } + + > .content-wrapper { + @include custom-scrollbar-themed; + padding: $spacing * 2; + + > .content { + margin: 0 auto; + width: 60%; + min-width: 570px; + max-width: 1000px; + } + } + + h2:not(:first-of-type) { + margin-top: $spacing; + } + + p { + line-height: 140%; + } + + a { + color: $colorInfo; + } + + .Select { + &__control { + box-shadow: 0 0 0 1px $borderFaintColor; + } + } +} \ No newline at end of file diff --git a/src/renderer/components/layout/page-layout.tsx b/src/renderer/components/layout/page-layout.tsx new file mode 100644 index 0000000000..5cfe5bad50 --- /dev/null +++ b/src/renderer/components/layout/page-layout.tsx @@ -0,0 +1,73 @@ +import "./page-layout.scss" + +import React from "react"; +import { observer } from "mobx-react"; +import { cssNames, IClassName } from "../../utils"; +import { Icon } from "../icon"; +import { navigation } from "../../navigation"; + +export interface PageLayoutProps extends React.DOMAttributes { + className?: IClassName; + header: React.ReactNode; + headerClass?: IClassName; + contentClass?: IClassName; + provideBackButtonNavigation?: boolean; + contentGaps?: boolean; + fullScreen?: boolean; // covers whole app view +} + +const defaultProps: Partial = { + provideBackButtonNavigation: true, + contentGaps: true, +} + +@observer +export class PageLayout extends React.Component { + static defaultProps = defaultProps as object; + + back = () => navigation.goBack(); + + async componentDidMount() { + window.addEventListener('keydown', this.onEscapeKey); + } + + componentWillUnmount() { + window.removeEventListener('keydown', this.onEscapeKey); + } + + onEscapeKey = (evt: KeyboardEvent) => { + if (!this.props.provideBackButtonNavigation) { + return; + } + if (evt.code === "Escape") { + evt.stopPropagation(); + this.back(); + } + } + + render() { + const { + className, contentClass, header, headerClass, provideBackButtonNavigation, + contentGaps, fullScreen, children, ...elemProps + } = this.props; + return ( +
+
+ {header} + {provideBackButtonNavigation && ( + + )} +
+
+
+ {children} +
+
+
+ ) + } +} diff --git a/src/renderer/components/layout/wizard-layout.scss b/src/renderer/components/layout/wizard-layout.scss index ac7ab13393..d82d081d61 100644 --- a/src/renderer/components/layout/wizard-layout.scss +++ b/src/renderer/components/layout/wizard-layout.scss @@ -8,13 +8,9 @@ grid-template-columns: 1fr 40%; > * { - @include custom-scrollbar; + @include custom-scrollbar-themed; --flex-gap: #{$spacing}; padding: $spacing; - - .theme-light & { - @include custom-scrollbar(dark); - } } > .head-col { diff --git a/src/renderer/components/mixins.scss b/src/renderer/components/mixins.scss index 0edc62eb3d..43983e8f02 100755 --- a/src/renderer/components/mixins.scss +++ b/src/renderer/components/mixins.scss @@ -6,6 +6,21 @@ @import "table/table.mixins"; @import "+network/network-mixins"; +@mixin custom-scrollbar-themed($invert: false) { + @if ($invert) { + @include custom-scrollbar(dark); + .theme-light & { + @include custom-scrollbar(light); + } + } @else { + // fits better with dark background + @include custom-scrollbar(light); + .theme-light & { + @include custom-scrollbar(dark); + } + } +} + @mixin custom-scrollbar($theme: light, $size: 7px, $borderSpacing: 5px) { $themes: ( light: #5f6064, diff --git a/src/renderer/components/tooltip/tooltip.tsx b/src/renderer/components/tooltip/tooltip.tsx index 3cbe0c8708..393651001f 100644 --- a/src/renderer/components/tooltip/tooltip.tsx +++ b/src/renderer/components/tooltip/tooltip.tsx @@ -11,6 +11,10 @@ export enum TooltipPosition { BOTTOM = "bottom", LEFT = "left", RIGHT = "right", + TOP_LEFT = "top_left", + TOP_RIGHT = "top_right", + BOTTOM_LEFT = "bottom_left", + BOTTOM_RIGHT = "bottom_right", } export interface TooltipProps { @@ -19,7 +23,7 @@ export interface TooltipProps { visible?: boolean; // initial visibility offset?: number; // offset from target element in pixels (all sides) usePortal?: boolean; // renders element outside of parent (in body), disable for "easy-styling", default: true - position?: TooltipPosition; + preferredPositions?: TooltipPosition | TooltipPosition[]; className?: IClassName; formatters?: TooltipContentFormatters; style?: React.CSSProperties; @@ -82,17 +86,25 @@ export class Tooltip extends React.Component { @autobind() refreshPosition() { - const { position } = this.props; + const { preferredPositions } = this.props; const { elem, targetElem } = this; - const positionPreference = new Set(); - if (typeof position !== "undefined") { - positionPreference.add(position); + let positions = new Set([ + TooltipPosition.RIGHT, + TooltipPosition.BOTTOM, + TooltipPosition.TOP, + TooltipPosition.LEFT, + TooltipPosition.TOP_RIGHT, + TooltipPosition.TOP_LEFT, + TooltipPosition.BOTTOM_RIGHT, + TooltipPosition.BOTTOM_LEFT, + ]); + if (preferredPositions) { + positions = new Set([ + ...[preferredPositions].flat(), + ...positions, + ]) } - positionPreference.add(TooltipPosition.RIGHT) - .add(TooltipPosition.BOTTOM) - .add(TooltipPosition.TOP) - .add(TooltipPosition.LEFT) // reset position first and get all possible client-rect area for tooltip element this.setPosition({ left: 0, top: 0 }); @@ -102,20 +114,20 @@ export class Tooltip extends React.Component { const { innerWidth: viewportWidth, innerHeight: viewportHeight } = window; // find proper position - for (const pos of positionPreference) { + for (const pos of positions) { const { left, top, right, bottom } = this.getPosition(pos, selfBounds, targetBounds) const fitsToWindow = left >= 0 && top >= 0 && right <= viewportWidth && bottom <= viewportHeight; if (fitsToWindow) { this.activePosition = pos; this.setPosition({ top, left }); - return; } } - const preferedPosition = Array.from(positionPreference)[0]; - const { left, top } = this.getPosition(preferedPosition, selfBounds, targetBounds) - this.activePosition = preferedPosition; + // apply fallback position if nothing helped from above + const fallbackPosition = Array.from(positions)[0]; + const { left, top } = this.getPosition(fallbackPosition, selfBounds, targetBounds) + this.activePosition = fallbackPosition; this.setPosition({ left, top }); } @@ -125,35 +137,54 @@ export class Tooltip extends React.Component { elemStyle.top = pos.top + "px" } - protected getPosition(position: TooltipPosition, selfBounds: DOMRect, targetBounds: DOMRect) { - let left: number - let top: number + protected getPosition(position: TooltipPosition, tooltipBounds: DOMRect, targetBounds: DOMRect) { + let left: number; + let top: number; const offset = this.props.offset; - const horizontalCenter = targetBounds.left + (targetBounds.width - selfBounds.width) / 2; - const verticalCenter = targetBounds.top + (targetBounds.height - selfBounds.height) / 2; + const horizontalCenter = targetBounds.left + (targetBounds.width - tooltipBounds.width) / 2; + const verticalCenter = targetBounds.top + (targetBounds.height - tooltipBounds.height) / 2; + const topCenter = targetBounds.top - tooltipBounds.height - offset; + const bottomCenter = targetBounds.bottom + offset; switch (position) { case "top": left = horizontalCenter; - top = targetBounds.top - selfBounds.height - offset; + top = topCenter; break; case "bottom": left = horizontalCenter; - top = targetBounds.bottom + offset; + top = bottomCenter; break; case "left": top = verticalCenter; - left = targetBounds.left - selfBounds.width - offset; + left = targetBounds.left - tooltipBounds.width - offset; break; case "right": top = verticalCenter; left = targetBounds.right + offset; break; + case "top_left": + left = targetBounds.left; + top = topCenter; + break; + case "top_right": + default: + left = targetBounds.right - tooltipBounds.width; + top = topCenter; + break; + case "bottom_left": + top = bottomCenter; + left = targetBounds.left; + break; + case "bottom_right": + top = bottomCenter; + left = targetBounds.right - tooltipBounds.width; + break; } return { left: left, top: top, - right: left + selfBounds.width, - bottom: top + selfBounds.height, + right: left + tooltipBounds.width, + bottom: top + tooltipBounds.height, }; } diff --git a/src/renderer/fonts/MaterialIcons-Regular.ttf b/src/renderer/fonts/MaterialIcons-Regular.ttf new file mode 100644 index 0000000000..e50801b3b6 Binary files /dev/null and b/src/renderer/fonts/MaterialIcons-Regular.ttf differ diff --git a/yarn.lock b/yarn.lock index f36ff35adb..fae2507115 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8644,11 +8644,6 @@ matcher@^3.0.0: dependencies: escape-string-regexp "^4.0.0" -material-design-icons@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/material-design-icons/-/material-design-icons-3.0.1.tgz#9a71c48747218ebca51e51a66da682038cdcb7bf" - integrity sha1-mnHEh0chjrylHlGmbaaCA4zct78= - md5-file@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-5.0.0.tgz#e519f631feca9c39e7f9ea1780b63c4745012e20"