mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Cleaning settings page view (#3156)
* Making inputs consistent Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Fixing hover effect in inputs Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Adding separators to sidebar menu Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Fine-tuning general section Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Fine-tuning hidden metrics area Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * EntityIcon in Settings sidebar Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Moving cluster icon settings on top Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Shrink Apply button a big Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
parent
1cc5607987
commit
7739b387cb
@ -281,7 +281,9 @@ export class MetricsSettings extends React.Component<Props> {
|
|||||||
waiting={this.inProgress}
|
waiting={this.inProgress}
|
||||||
onClick={() => this.save()}
|
onClick={() => this.save()}
|
||||||
primary
|
primary
|
||||||
disabled={!this.changed} />
|
disabled={!this.changed}
|
||||||
|
className="w-60 h-14"
|
||||||
|
/>
|
||||||
|
|
||||||
{this.canUpgrade && (<small className="hint">
|
{this.canUpgrade && (<small className="hint">
|
||||||
An update is available for enabled metrics components.
|
An update is available for enabled metrics components.
|
||||||
|
|||||||
@ -33,6 +33,7 @@ import { EntitySettingRegistry } from "../../../extensions/registries";
|
|||||||
import type { EntitySettingsRouteParams } from "../../../common/routes";
|
import type { EntitySettingsRouteParams } from "../../../common/routes";
|
||||||
import { groupBy } from "lodash";
|
import { groupBy } from "lodash";
|
||||||
import { SettingLayout } from "../layout/setting-layout";
|
import { SettingLayout } from "../layout/setting-layout";
|
||||||
|
import { HotbarIcon } from "../hotbar/hotbar-icon";
|
||||||
|
|
||||||
interface Props extends RouteComponentProps<EntitySettingsRouteParams> {
|
interface Props extends RouteComponentProps<EntitySettingsRouteParams> {
|
||||||
}
|
}
|
||||||
@ -83,10 +84,19 @@ export class EntitySettings extends React.Component<Props> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className="flex items-center pb-8">
|
||||||
|
<HotbarIcon
|
||||||
|
uid={this.entity.metadata.uid}
|
||||||
|
title={this.entity.metadata.name}
|
||||||
|
source={this.entity.metadata.source}
|
||||||
|
src={this.entity.spec.icon?.src}
|
||||||
|
/>
|
||||||
<h2>{this.entity.metadata.name}</h2>
|
<h2>{this.entity.metadata.name}</h2>
|
||||||
|
</div>
|
||||||
<Tabs className="flex column" scrollable={false} onChange={this.onTabChange} value={this.activeTab}>
|
<Tabs className="flex column" scrollable={false} onChange={this.onTabChange} value={this.activeTab}>
|
||||||
{ groups.map((group, groupIndex) => (
|
{ groups.map((group, groupIndex) => (
|
||||||
<React.Fragment key={`group-${groupIndex}`}>
|
<React.Fragment key={`group-${groupIndex}`}>
|
||||||
|
<hr/>
|
||||||
<div className="header">{group[0]}</div>
|
<div className="header">{group[0]}</div>
|
||||||
{ group[1].map((setting, index) => (
|
{ group[1].map((setting, index) => (
|
||||||
<Tab
|
<Tab
|
||||||
|
|||||||
@ -45,6 +45,7 @@ import { Install } from "./install";
|
|||||||
import { InstalledExtensions } from "./installed-extensions";
|
import { InstalledExtensions } from "./installed-extensions";
|
||||||
import { Notice } from "./notice";
|
import { Notice } from "./notice";
|
||||||
import { SettingLayout } from "../layout/setting-layout";
|
import { SettingLayout } from "../layout/setting-layout";
|
||||||
|
import { docsUrl } from "../../../common/vars";
|
||||||
|
|
||||||
function getMessageFromError(error: any): string {
|
function getMessageFromError(error: any): string {
|
||||||
if (!error || typeof error !== "object") {
|
if (!error || typeof error !== "object") {
|
||||||
@ -514,7 +515,13 @@ export class Extensions extends React.Component<Props> {
|
|||||||
<section>
|
<section>
|
||||||
<h1>Extensions</h1>
|
<h1>Extensions</h1>
|
||||||
|
|
||||||
<Notice/>
|
<Notice>
|
||||||
|
<p>
|
||||||
|
Add new features via Lens Extensions.{" "}
|
||||||
|
Check out <a href={`${docsUrl}/extensions/`} target="_blank" rel="noreferrer">docs</a>{" "}
|
||||||
|
and list of <a href="https://github.com/lensapp/lens-extensions/blob/main/README.md" target="_blank" rel="noreferrer">available extensions</a>.
|
||||||
|
</p>
|
||||||
|
</Notice>
|
||||||
|
|
||||||
<Install
|
<Install
|
||||||
supportedFormats={supportedFormats}
|
supportedFormats={supportedFormats}
|
||||||
|
|||||||
@ -20,17 +20,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import styles from "./notice.module.css";
|
import styles from "./notice.module.css";
|
||||||
import React from "react";
|
import React, { DOMAttributes } from "react";
|
||||||
import { docsUrl } from "../../../common/vars";
|
|
||||||
|
|
||||||
export function Notice() {
|
interface Props extends DOMAttributes<any> {}
|
||||||
|
|
||||||
|
export function Notice(props: Props) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.notice}>
|
<div className={styles.notice}>
|
||||||
<p>
|
{props.children}
|
||||||
Add new features via Lens Extensions.{" "}
|
|
||||||
Check out <a href={`${docsUrl}/extensions/`} target="_blank" rel="noreferrer">docs</a>{" "}
|
|
||||||
and list of <a href="https://github.com/lensapp/lens-extensions/blob/main/README.md" target="_blank" rel="noreferrer">available extensions</a>.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,12 +40,16 @@ export function GeneralSettings({ entity }: EntitySettingViewProps) {
|
|||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<section>
|
<section>
|
||||||
|
<div className="flex">
|
||||||
|
<div className="flex-grow pr-8">
|
||||||
<components.ClusterNameSetting cluster={cluster} />
|
<components.ClusterNameSetting cluster={cluster} />
|
||||||
</section>
|
</div>
|
||||||
<section>
|
<div>
|
||||||
<components.ClusterIconSetting cluster={cluster} entity={entity as KubernetesCluster} />
|
<components.ClusterIconSetting cluster={cluster} entity={entity as KubernetesCluster} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section className="small">
|
||||||
<components.ClusterKubeconfig cluster={cluster} />
|
<components.ClusterKubeconfig cluster={cluster} />
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
@ -106,10 +110,9 @@ export function MetricsSettings({ entity }: EntitySettingViewProps) {
|
|||||||
<section>
|
<section>
|
||||||
<components.ClusterPrometheusSetting cluster={cluster} />
|
<components.ClusterPrometheusSetting cluster={cluster} />
|
||||||
</section>
|
</section>
|
||||||
|
<hr/>
|
||||||
<section>
|
<section>
|
||||||
<components.ClusterMetricsSetting cluster={cluster} />
|
<components.ClusterMetricsSetting cluster={cluster} />
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<components.ShowMetricsSetting cluster={cluster} />
|
<components.ShowMetricsSetting cluster={cluster} />
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -54,6 +54,7 @@ export class ClusterAccessibleNamespaces extends React.Component<Props> {
|
|||||||
this.namespaces.delete(oldNamesapce);
|
this.namespaces.delete(oldNamesapce);
|
||||||
this.props.cluster.accessibleNamespaces = Array.from(this.namespaces);
|
this.props.cluster.accessibleNamespaces = Array.from(this.namespaces);
|
||||||
}}
|
}}
|
||||||
|
inputTheme="round-black"
|
||||||
/>
|
/>
|
||||||
<small className="hint">
|
<small className="hint">
|
||||||
This setting is useful for manually specifying which namespaces you have access to. This is useful when you do not have permissions to list namespaces.
|
This setting is useful for manually specifying which namespaces you have access to. This is useful when you do not have permissions to list namespaces.
|
||||||
|
|||||||
@ -21,15 +21,13 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { Cluster } from "../../../../main/cluster";
|
import type { Cluster } from "../../../../main/cluster";
|
||||||
//import { FilePicker, OverSizeLimitStyle } from "../../file-picker";
|
|
||||||
import { boundMethod } from "../../../utils";
|
import { boundMethod } from "../../../utils";
|
||||||
import { Button } from "../../button";
|
|
||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { SubTitle } from "../../layout/sub-title";
|
|
||||||
import { HotbarIcon } from "../../hotbar/hotbar-icon";
|
import { HotbarIcon } from "../../hotbar/hotbar-icon";
|
||||||
import type { KubernetesCluster } from "../../../../common/catalog-entities";
|
import type { KubernetesCluster } from "../../../../common/catalog-entities";
|
||||||
import { FilePicker, OverSizeLimitStyle } from "../../file-picker";
|
import { FilePicker, OverSizeLimitStyle } from "../../file-picker";
|
||||||
|
import { MenuActions, MenuItem } from "../../menu";
|
||||||
|
|
||||||
enum GeneralInputStatus {
|
enum GeneralInputStatus {
|
||||||
CLEAN = "clean",
|
CLEAN = "clean",
|
||||||
@ -46,6 +44,8 @@ export class ClusterIconSetting extends React.Component<Props> {
|
|||||||
@observable status = GeneralInputStatus.CLEAN;
|
@observable status = GeneralInputStatus.CLEAN;
|
||||||
@observable errorText?: string;
|
@observable errorText?: string;
|
||||||
|
|
||||||
|
private element = React.createRef<HTMLDivElement>();
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
async onIconPick([file]: File[]) {
|
async onIconPick([file]: File[]) {
|
||||||
const { cluster } = this.props;
|
const { cluster } = this.props;
|
||||||
@ -66,16 +66,11 @@ export class ClusterIconSetting extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getClearButton() {
|
@boundMethod
|
||||||
if (this.props.cluster.preferences.icon) {
|
onUploadClick() {
|
||||||
return <Button
|
const input = this.element.current.querySelector("input[type=file]") as HTMLInputElement;
|
||||||
label="Clear"
|
|
||||||
tooltip="Revert back to default icon"
|
|
||||||
onClick={() => this.onIconPick([])}
|
|
||||||
/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
input.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -87,24 +82,32 @@ export class ClusterIconSetting extends React.Component<Props> {
|
|||||||
title={entity.metadata.name}
|
title={entity.metadata.name}
|
||||||
source={entity.metadata.source}
|
source={entity.metadata.source}
|
||||||
src={entity.spec.icon?.src}
|
src={entity.spec.icon?.src}
|
||||||
|
size={53}
|
||||||
/>
|
/>
|
||||||
<span style={{marginRight: "var(--unit)"}}>Browse for new icon...</span>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div ref={this.element}>
|
||||||
<SubTitle title="Cluster Icon" />
|
<div className="file-loader flex flex-row items-center">
|
||||||
<div className="file-loader">
|
<div className="mr-5">
|
||||||
<FilePicker
|
<FilePicker
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
label={label}
|
label={label}
|
||||||
onOverSizeLimit={OverSizeLimitStyle.FILTER}
|
onOverSizeLimit={OverSizeLimitStyle.FILTER}
|
||||||
handler={this.onIconPick}
|
handler={this.onIconPick}
|
||||||
/>
|
/>
|
||||||
{this.getClearButton()}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
<MenuActions toolbar={false} autoCloseOnSelect={true} triggerIcon={{ material: "more_horiz" }}>
|
||||||
|
<MenuItem onClick={this.onUploadClick}>
|
||||||
|
Upload Icon
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={() => this.onIconPick([])} disabled={!this.props.cluster.preferences.icon}>
|
||||||
|
Clear
|
||||||
|
</MenuItem>
|
||||||
|
</MenuActions>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import { observer } from "mobx-react";
|
|||||||
import { SubTitle } from "../../layout/sub-title";
|
import { SubTitle } from "../../layout/sub-title";
|
||||||
import { boundMethod } from "../../../../common/utils";
|
import { boundMethod } from "../../../../common/utils";
|
||||||
import { shell } from "electron";
|
import { shell } from "electron";
|
||||||
|
import { Notice } from "../../+extensions/notice";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
cluster: Cluster;
|
cluster: Cluster;
|
||||||
@ -42,14 +43,12 @@ export class ClusterKubeconfig extends React.Component<Props> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<Notice>
|
||||||
<SubTitle title="Kubeconfig" />
|
<SubTitle title="Kubeconfig" />
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
<a className="link value" onClick={this.openKubeconfig}>{this.props.cluster.kubeConfigPath}</a>
|
<a className="link value" onClick={this.openKubeconfig}>{this.props.cluster.kubeConfigPath}</a>
|
||||||
</span>
|
</span>
|
||||||
|
</Notice>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,6 +100,7 @@ export class ClusterMetricsSetting extends React.Component<Props> {
|
|||||||
options={Object.values(ClusterMetricsResourceType)}
|
options={Object.values(ClusterMetricsResourceType)}
|
||||||
onChange={this.onChangeSelect}
|
onChange={this.onChangeSelect}
|
||||||
formatOptionLabel={this.formatOptionLabel}
|
formatOptionLabel={this.formatOptionLabel}
|
||||||
|
themeName="lens"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
primary
|
primary
|
||||||
@ -118,7 +119,7 @@ export class ClusterMetricsSetting extends React.Component<Props> {
|
|||||||
render() {
|
render() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="MetricsSelect">
|
<div className="MetricsSelec0 mb-5">
|
||||||
<SubTitle title={"Hide metrics from the UI"}/>
|
<SubTitle title={"Hide metrics from the UI"}/>
|
||||||
<div className="flex gaps">
|
<div className="flex gaps">
|
||||||
{this.renderMetricsSelect()}
|
{this.renderMetricsSelect()}
|
||||||
|
|||||||
@ -138,14 +138,17 @@ export class ClusterPrometheusSetting extends React.Component<Props> {
|
|||||||
this.onSaveProvider();
|
this.onSaveProvider();
|
||||||
}}
|
}}
|
||||||
options={this.options}
|
options={this.options}
|
||||||
|
themeName="lens"
|
||||||
/>
|
/>
|
||||||
<small className="hint">What query format is used to fetch metrics from Prometheus</small>
|
<small className="hint">What query format is used to fetch metrics from Prometheus</small>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
{this.canEditPrometheusPath && (
|
{this.canEditPrometheusPath && (
|
||||||
|
<>
|
||||||
|
<hr/>
|
||||||
<section>
|
<section>
|
||||||
<p>Prometheus service address.</p>
|
<SubTitle title="Prometheus service address" />
|
||||||
<Input
|
<Input
|
||||||
theme="round-black"
|
theme="round-black"
|
||||||
value={this.path}
|
value={this.path}
|
||||||
@ -158,6 +161,7 @@ export class ClusterPrometheusSetting extends React.Component<Props> {
|
|||||||
({"<namespace>/<service>:<port>"}). {productName} tries to auto-detect address if left empty.
|
({"<namespace>/<service>:<port>"}). {productName} tries to auto-detect address if left empty.
|
||||||
</small>
|
</small>
|
||||||
</section>
|
</section>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import type { Cluster } from "../../../../main/cluster";
|
|||||||
import { observable, reaction, makeObservable } from "mobx";
|
import { observable, reaction, makeObservable } from "mobx";
|
||||||
import { Badge } from "../../badge/badge";
|
import { Badge } from "../../badge/badge";
|
||||||
import { Icon } from "../../icon/icon";
|
import { Icon } from "../../icon/icon";
|
||||||
|
import { Notice } from "../../+extensions/notice";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
cluster: Cluster;
|
cluster: Cluster;
|
||||||
@ -55,14 +56,20 @@ export class ShowMetricsSetting extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderMetrics() {
|
renderMetrics() {
|
||||||
|
const metrics = Array.from(this.hiddenMetrics);
|
||||||
|
|
||||||
|
if (!metrics.length) {
|
||||||
|
return (
|
||||||
|
<div className="flex-grow text-center">All metrics are visible on the UI</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
metrics.map(name => {
|
||||||
Array.from(this.hiddenMetrics).map(name => {
|
|
||||||
const tooltipId = `${name}`;
|
const tooltipId = `${name}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Badge key={name}>
|
<Badge key={name} flat>
|
||||||
<span id={tooltipId}>{name}</span>
|
<span id={tooltipId}>{name}</span>
|
||||||
<Icon
|
<Icon
|
||||||
smallest
|
smallest
|
||||||
@ -79,9 +86,11 @@ export class ShowMetricsSetting extends React.Component<Props> {
|
|||||||
render() {
|
render() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="MetricsSelect flex wrap gaps">
|
<Notice>
|
||||||
|
<div className="MetricsSelect flex wrap gaps leading-relaxed">
|
||||||
{this.renderMetrics()}
|
{this.renderMetrics()}
|
||||||
</div>
|
</div>
|
||||||
|
</Notice>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,10 @@
|
|||||||
.el-contents {
|
.el-contents {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
&:not(:empty) {
|
||||||
margin: $padding 0px;
|
margin: $padding 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.el-value-remove {
|
.el-value-remove {
|
||||||
.Icon {
|
.Icon {
|
||||||
|
|||||||
@ -25,7 +25,7 @@ import { observer } from "mobx-react";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { Input } from "../input";
|
import { Input, InputProps } from "../input";
|
||||||
import { boundMethod } from "../../utils";
|
import { boundMethod } from "../../utils";
|
||||||
|
|
||||||
export interface Props<T> {
|
export interface Props<T> {
|
||||||
@ -37,11 +37,13 @@ export interface Props<T> {
|
|||||||
// An optional prop used to convert T to a displayable string
|
// An optional prop used to convert T to a displayable string
|
||||||
// defaults to `String`
|
// defaults to `String`
|
||||||
renderItem?: (item: T, index: number) => React.ReactNode,
|
renderItem?: (item: T, index: number) => React.ReactNode,
|
||||||
|
inputTheme?: InputProps["theme"];
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultProps: Partial<Props<any>> = {
|
const defaultProps: Partial<Props<any>> = {
|
||||||
placeholder: "Add new item...",
|
placeholder: "Add new item...",
|
||||||
renderItem: (item: any, index: number) => <React.Fragment key={index}>{item}</React.Fragment>
|
renderItem: (item: any, index: number) => <React.Fragment key={index}>{item}</React.Fragment>,
|
||||||
|
inputTheme: "round"
|
||||||
};
|
};
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -59,13 +61,13 @@ export class EditableList<T> extends React.Component<Props<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { items, remove, renderItem, placeholder } = this.props;
|
const { items, remove, renderItem, placeholder, inputTheme } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="EditableList">
|
<div className="EditableList">
|
||||||
<div className="el-header">
|
<div className="el-header">
|
||||||
<Input
|
<Input
|
||||||
theme="round"
|
theme={inputTheme}
|
||||||
onSubmit={this.onSubmit}
|
onSubmit={this.onSubmit}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -227,12 +227,12 @@ export class FilePicker extends React.Component<Props> {
|
|||||||
|
|
||||||
getIconRight(): React.ReactNode {
|
getIconRight(): React.ReactNode {
|
||||||
switch (this.status) {
|
switch (this.status) {
|
||||||
case FileInputStatus.CLEAR:
|
|
||||||
return <Icon className="clean" material="cloud_upload"></Icon>;
|
|
||||||
case FileInputStatus.PROCESSING:
|
case FileInputStatus.PROCESSING:
|
||||||
return <Spinner />;
|
return <Spinner />;
|
||||||
case FileInputStatus.ERROR:
|
case FileInputStatus.ERROR:
|
||||||
return <Icon material="error" title={this.errorText}></Icon>;
|
return <Icon material="error" title={this.errorText}></Icon>;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -136,10 +136,15 @@
|
|||||||
border-color: var(--inputControlBorder);
|
border-color: var(--inputControlBorder);
|
||||||
color: var(--textColorTertiary);
|
color: var(--textColorTertiary);
|
||||||
padding: $padding;
|
padding: $padding;
|
||||||
|
transition: border-color 0.1s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: var(--inputControlHoverBorder);
|
border-color: var(--inputControlHoverBorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
border-color: $colorInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,17 +20,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.SettingLayout {
|
.SettingLayout {
|
||||||
--width: 75%;
|
|
||||||
--nav-width: 180px;
|
|
||||||
--nav-column-width: 30vw;
|
--nav-column-width: 30vw;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: grid !important;
|
display: grid;
|
||||||
color: var(--settingsColor);
|
color: var(--settingsColor);
|
||||||
|
position: fixed;
|
||||||
@include media("<1000px") {
|
z-index: 13!important;
|
||||||
--width: 85%;
|
left: 0;
|
||||||
}
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: unset;
|
||||||
|
background-color: var(--settingsBackground);
|
||||||
|
|
||||||
&.showNavigation {
|
&.showNavigation {
|
||||||
grid-template-columns: var(--nav-column-width) 1fr;
|
grid-template-columns: var(--nav-column-width) 1fr;
|
||||||
@ -40,18 +42,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// covers whole app view area
|
|
||||||
&.showOnTop {
|
|
||||||
position: fixed !important; // allow to cover ClustersMenu
|
|
||||||
z-index: 13;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
height: unset;
|
|
||||||
background-color: var(--settingsBackground);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .sidebarRegion {
|
> .sidebarRegion {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
@ -63,12 +53,25 @@
|
|||||||
padding: 60px 0 60px 20px;
|
padding: 60px 0 60px 20px;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
margin-bottom: 10px;
|
font-size: 15px;
|
||||||
font-size: 18px;
|
|
||||||
padding: 6px 10px;
|
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
color: var(--textColorAccent);
|
color: var(--textColorAccent);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
padding-right: 20px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 20px;
|
||||||
|
height: 1px;
|
||||||
|
border-top: thin solid var(--hrColor);
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.Tabs {
|
.Tabs {
|
||||||
@ -78,6 +81,7 @@
|
|||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
color: var(--textColorPrimary);
|
||||||
|
|
||||||
&:first-child {
|
&:first-child {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
@ -112,9 +116,14 @@
|
|||||||
|
|
||||||
> .label {
|
> .label {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.HotbarIcon {
|
||||||
|
margin: 0 11px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +133,9 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
> .content {
|
> .content {
|
||||||
width: var(--width);
|
width: 100%;
|
||||||
|
max-width: 740px;
|
||||||
|
min-width: 460px;
|
||||||
padding: 60px 40px 80px;
|
padding: 60px 40px 80px;
|
||||||
|
|
||||||
> section {
|
> section {
|
||||||
@ -157,7 +168,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.Icon {
|
.Icon {
|
||||||
color: var(--textColorSecondary);
|
color: var(--textColorTertiary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +211,7 @@
|
|||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
@ -210,6 +221,7 @@
|
|||||||
.hint {
|
.hint {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.SubTitle {
|
.SubTitle {
|
||||||
|
|||||||
@ -81,7 +81,7 @@ export class SettingLayout extends React.Component<SettingLayoutProps> {
|
|||||||
contentClass, provideBackButtonNavigation,
|
contentClass, provideBackButtonNavigation,
|
||||||
contentGaps, navigation, children, ...elemProps
|
contentGaps, navigation, children, ...elemProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const className = cssNames("SettingLayout", "showOnTop", { showNavigation: navigation }, this.props.className);
|
const className = cssNames("SettingLayout", { showNavigation: navigation }, this.props.className);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div {...elemProps} className={className}>
|
<div {...elemProps} className={className}>
|
||||||
|
|||||||
@ -213,6 +213,7 @@ html {
|
|||||||
:hover {
|
:hover {
|
||||||
&.Select__control {
|
&.Select__control {
|
||||||
box-shadow: 0 0 0 1px var(--inputControlHoverBorder);
|
box-shadow: 0 0 0 1px var(--inputControlHoverBorder);
|
||||||
|
transition: box-shadow 0.1s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user