mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Preferences page redesign (#2446)
* Removing header part Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Restyling PageLayout Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Restyling .round-black Input Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Adding Tab navigation to Preferences Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Styling Application tab Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Add esc button Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Add media queries Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Introducting Switcher component Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Styling Proxy tab Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Moving start-up switcher to Other tab Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Styling Kubernetes tab Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Styling Extensions tab Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Styling inputs and selects Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Styling helm chart section Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Create a telemetry tab with extensions Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Adding lens Select theme Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Remove Other tab Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Fix mainBackground color Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Simplifying Tabs boilerplate Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Replacing button font Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Fixing one-column settings layout Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Fixing integration tests Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Fixin tests harder Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Showing bottom bar in workspaces Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
parent
33c405bdcf
commit
84cc0cdf55
@ -8,6 +8,7 @@ export default class SurveyRendererExtension extends LensRendererExtension {
|
|||||||
appPreferences = [
|
appPreferences = [
|
||||||
{
|
{
|
||||||
title: "In-App Surveys",
|
title: "In-App Surveys",
|
||||||
|
showInPreferencesTab: "telemetry",
|
||||||
components: {
|
components: {
|
||||||
Hint: () => <SurveyPreferenceHint/>,
|
Hint: () => <SurveyPreferenceHint/>,
|
||||||
Input: () => <SurveyPreferenceInput survey={surveyPreferencesStore}/>
|
Input: () => <SurveyPreferenceInput survey={surveyPreferencesStore}/>
|
||||||
|
|||||||
@ -8,6 +8,7 @@ export default class TelemetryRendererExtension extends LensRendererExtension {
|
|||||||
appPreferences = [
|
appPreferences = [
|
||||||
{
|
{
|
||||||
title: "Telemetry & Usage Tracking",
|
title: "Telemetry & Usage Tracking",
|
||||||
|
showInPreferencesTab: "telemetry",
|
||||||
id: "telemetry-tracking",
|
id: "telemetry-tracking",
|
||||||
components: {
|
components: {
|
||||||
Hint: () => <TelemetryPreferenceHint/>,
|
Hint: () => <TelemetryPreferenceHint/>,
|
||||||
|
|||||||
@ -36,7 +36,7 @@ describe("Lens integration tests", () => {
|
|||||||
|
|
||||||
it('shows "add cluster"', async () => {
|
it('shows "add cluster"', async () => {
|
||||||
await app.electron.ipcRenderer.send("test-menu-item-click", "File", "Add Cluster");
|
await app.electron.ipcRenderer.send("test-menu-item-click", "File", "Add Cluster");
|
||||||
await app.client.waitUntilTextExists("h2", "Add Cluster");
|
await app.client.waitUntilTextExists("h2", "Add Clusters from Kubeconfig");
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("preferences page", () => {
|
describe("preferences page", () => {
|
||||||
@ -44,7 +44,17 @@ describe("Lens integration tests", () => {
|
|||||||
const appName: string = process.platform === "darwin" ? "Lens" : "File";
|
const appName: string = process.platform === "darwin" ? "Lens" : "File";
|
||||||
|
|
||||||
await app.electron.ipcRenderer.send("test-menu-item-click", appName, "Preferences");
|
await app.electron.ipcRenderer.send("test-menu-item-click", appName, "Preferences");
|
||||||
await app.client.waitUntilTextExists("h2", "Preferences");
|
await app.client.waitUntilTextExists("[data-testid=application-header]", "APPLICATION");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows all tabs and their contents", async () => {
|
||||||
|
await app.client.click("[data-testid=application-tab]");
|
||||||
|
await app.client.click("[data-testid=proxy-tab]");
|
||||||
|
await app.client.waitUntilTextExists("[data-testid=proxy-header]", "PROXY");
|
||||||
|
await app.client.click("[data-testid=kube-tab]");
|
||||||
|
await app.client.waitUntilTextExists("[data-testid=kubernetes-header]", "KUBERNETES");
|
||||||
|
await app.client.click("[data-testid=telemetry-tab]");
|
||||||
|
await app.client.waitUntilTextExists("[data-testid=telemetry-header]", "TELEMETRY");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ensures helm repos", async () => {
|
it("ensures helm repos", async () => {
|
||||||
@ -54,7 +64,8 @@ describe("Lens integration tests", () => {
|
|||||||
fail("Lens failed to add Bitnami repository");
|
fail("Lens failed to add Bitnami repository");
|
||||||
}
|
}
|
||||||
|
|
||||||
await app.client.waitUntilTextExists("div.repos #message-bitnami", repos[0].name); // wait for the helm-cli to fetch the repo(s)
|
await app.client.click("[data-testid=kube-tab]");
|
||||||
|
await app.client.waitUntilTextExists("div.repos .repoName", repos[0].name); // wait for the helm-cli to fetch the repo(s)
|
||||||
await app.client.click("#HelmRepoSelect"); // click the repo select to activate the drop-down
|
await app.client.click("#HelmRepoSelect"); // click the repo select to activate the drop-down
|
||||||
await app.client.waitUntilTextExists("div.Select__option", ""); // wait for at least one option to appear (any text)
|
await app.client.waitUntilTextExists("div.Select__option", ""); // wait for at least one option to appear (any text)
|
||||||
});
|
});
|
||||||
|
|||||||
@ -80,7 +80,7 @@ export async function appStart() {
|
|||||||
export async function clickWhatsNew(app: Application) {
|
export async function clickWhatsNew(app: Application) {
|
||||||
await app.client.waitUntilTextExists("h1", "What's new?");
|
await app.client.waitUntilTextExists("h1", "What's new?");
|
||||||
await app.client.click("button.primary");
|
await app.client.click("button.primary");
|
||||||
await app.client.waitUntilTextExists("h2", "default");
|
await app.client.waitUntilTextExists("h5", "Clusters");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function clickWelcomeNotification(app: Application) {
|
export async function clickWelcomeNotification(app: Application) {
|
||||||
@ -89,7 +89,7 @@ export async function clickWelcomeNotification(app: Application) {
|
|||||||
if (itemsText === "0 item") {
|
if (itemsText === "0 item") {
|
||||||
// welcome notification should be present, dismiss it
|
// welcome notification should be present, dismiss it
|
||||||
await app.client.waitUntilTextExists("div.message", "Welcome!");
|
await app.client.waitUntilTextExists("div.message", "Welcome!");
|
||||||
await app.client.click("i.Icon.close");
|
await app.client.click(".notification i.Icon.close");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export interface AppPreferenceComponents {
|
|||||||
export interface AppPreferenceRegistration {
|
export interface AppPreferenceRegistration {
|
||||||
title: string;
|
title: string;
|
||||||
id?: string;
|
id?: string;
|
||||||
|
showInPreferencesTab?: string;
|
||||||
components: AppPreferenceComponents;
|
components: AppPreferenceComponents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,11 +2,9 @@
|
|||||||
--width: 100%;
|
--width: 100%;
|
||||||
--height: 100%;
|
--height: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
bottom: 22px; // Making bottom bar visible
|
||||||
|
|
||||||
|
|
||||||
.content-wrapper {
|
.content-wrapper {
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
margin: unset;
|
margin: unset;
|
||||||
max-width: unset;
|
max-width: unset;
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
.HelmCharts {
|
.HelmCharts {
|
||||||
.repos {
|
.repos {
|
||||||
margin-top: var(--margin);
|
margin-top: 20px;
|
||||||
|
|
||||||
.Badge {
|
.repo {
|
||||||
display: flex;
|
background: var(--inputControlBackground);
|
||||||
margin-bottom: 1px!important;
|
border-radius: 4px;
|
||||||
padding: 6px 8px;
|
padding: 12px 16px;
|
||||||
|
box-shadow: 0 0 0 1px var(--secondaryBackground);
|
||||||
|
|
||||||
|
.repoName {
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repoUrl {
|
||||||
|
color: var(--textColorDimmed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,12 +4,10 @@ import React from "react";
|
|||||||
import { action, computed, observable } from "mobx";
|
import { action, computed, observable } from "mobx";
|
||||||
|
|
||||||
import { HelmRepo, repoManager } from "../../../main/helm/helm-repo-manager";
|
import { HelmRepo, repoManager } from "../../../main/helm/helm-repo-manager";
|
||||||
import { Badge } from "../badge";
|
|
||||||
import { Button } from "../button";
|
import { Button } from "../button";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { Notifications } from "../notifications";
|
import { Notifications } from "../notifications";
|
||||||
import { Select, SelectOption } from "../select";
|
import { Select, SelectOption } from "../select";
|
||||||
import { Tooltip } from "../tooltip";
|
|
||||||
import { AddHelmRepoDialog } from "./add-helm-repo-dialog";
|
import { AddHelmRepoDialog } from "./add-helm-repo-dialog";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
|
|
||||||
@ -106,6 +104,7 @@ export class HelmCharts extends React.Component {
|
|||||||
formatOptionLabel={this.formatOptionLabel}
|
formatOptionLabel={this.formatOptionLabel}
|
||||||
controlShouldRenderValue={false}
|
controlShouldRenderValue={false}
|
||||||
className="box grow"
|
className="box grow"
|
||||||
|
themeName="lens"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
primary
|
primary
|
||||||
@ -116,20 +115,18 @@ export class HelmCharts extends React.Component {
|
|||||||
<AddHelmRepoDialog onAddRepo={() => this.loadRepos()}/>
|
<AddHelmRepoDialog onAddRepo={() => this.loadRepos()}/>
|
||||||
<div className="repos flex gaps column">
|
<div className="repos flex gaps column">
|
||||||
{Array.from(this.addedRepos).map(([name, repo]) => {
|
{Array.from(this.addedRepos).map(([name, repo]) => {
|
||||||
const tooltipId = `message-${name}`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Badge key={name} className="added-repo flex gaps align-center justify-space-between">
|
<div key={name} className="repo flex gaps align-center justify-space-between">
|
||||||
<span id={tooltipId} className="repo">{name}</span>
|
<div>
|
||||||
|
<div className="repoName">{name}</div>
|
||||||
|
<div className="repoUrl">{repo.url}</div>
|
||||||
|
</div>
|
||||||
<Icon
|
<Icon
|
||||||
material="delete"
|
material="delete"
|
||||||
onClick={() => this.removeRepo(repo)}
|
onClick={() => this.removeRepo(repo)}
|
||||||
tooltip="Remove"
|
tooltip="Remove"
|
||||||
/>
|
/>
|
||||||
<Tooltip targetId={tooltipId} formatters={{ narrow: true }}>
|
</div>
|
||||||
{repo.url}
|
|
||||||
</Tooltip>
|
|
||||||
</Badge>
|
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Checkbox } from "../checkbox";
|
|
||||||
import { Input, InputValidators } from "../input";
|
import { Input, InputValidators } from "../input";
|
||||||
import { SubTitle } from "../layout/sub-title";
|
import { SubTitle } from "../layout/sub-title";
|
||||||
import { UserPreferences, userStore } from "../../../common/user-store";
|
import { UserPreferences, userStore } from "../../../common/user-store";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { bundledKubectlPath } from "../../../main/kubectl";
|
import { bundledKubectlPath } from "../../../main/kubectl";
|
||||||
import { SelectOption, Select } from "../select";
|
import { SelectOption, Select } from "../select";
|
||||||
|
import { FormSwitch, Switcher } from "../switch";
|
||||||
|
|
||||||
export const KubectlBinaries = observer(({ preferences }: { preferences: UserPreferences }) => {
|
export const KubectlBinaries = observer(({ preferences }: { preferences: UserPreferences }) => {
|
||||||
const [downloadPath, setDownloadPath] = useState(preferences.downloadBinariesPath || "");
|
const [downloadPath, setDownloadPath] = useState(preferences.downloadBinariesPath || "");
|
||||||
@ -24,12 +24,23 @@ export const KubectlBinaries = observer(({ preferences }: { preferences: UserPre
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SubTitle title="Automatic kubectl binary download"/>
|
<section className="small">
|
||||||
<Checkbox
|
<SubTitle title="Kubectl binary download"/>
|
||||||
label="Download kubectl binaries matching the Kubernetes cluster version"
|
<FormSwitch
|
||||||
value={preferences.downloadKubectlBinaries}
|
control={
|
||||||
onChange={downloadKubectlBinaries => preferences.downloadKubectlBinaries = downloadKubectlBinaries}
|
<Switcher
|
||||||
|
checked={preferences.downloadKubectlBinaries}
|
||||||
|
onChange={v => preferences.downloadKubectlBinaries = v.target.checked}
|
||||||
|
name="kubectl-download"
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
|
label="Download kubectl binaries matching the Kubernetes cluster version"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<hr className="small"/>
|
||||||
|
|
||||||
|
<section className="small">
|
||||||
<SubTitle title="Download mirror" />
|
<SubTitle title="Download mirror" />
|
||||||
<Select
|
<Select
|
||||||
placeholder="Download mirror for kubectl"
|
placeholder="Download mirror for kubectl"
|
||||||
@ -37,7 +48,13 @@ export const KubectlBinaries = observer(({ preferences }: { preferences: UserPre
|
|||||||
value={preferences.downloadMirror}
|
value={preferences.downloadMirror}
|
||||||
onChange={({ value }: SelectOption) => preferences.downloadMirror = value}
|
onChange={({ value }: SelectOption) => preferences.downloadMirror = value}
|
||||||
disabled={!preferences.downloadKubectlBinaries}
|
disabled={!preferences.downloadKubectlBinaries}
|
||||||
|
themeName="lens"
|
||||||
/>
|
/>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<hr className="small"/>
|
||||||
|
|
||||||
|
<section className="small">
|
||||||
<SubTitle title="Directory for binaries" />
|
<SubTitle title="Directory for binaries" />
|
||||||
<Input
|
<Input
|
||||||
theme="round-black"
|
theme="round-black"
|
||||||
@ -48,9 +65,14 @@ export const KubectlBinaries = observer(({ preferences }: { preferences: UserPre
|
|||||||
onBlur={save}
|
onBlur={save}
|
||||||
disabled={!preferences.downloadKubectlBinaries}
|
disabled={!preferences.downloadKubectlBinaries}
|
||||||
/>
|
/>
|
||||||
<small className="hint">
|
<div className="hint">
|
||||||
The directory to download binaries into.
|
The directory to download binaries into.
|
||||||
</small>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<hr className="small"/>
|
||||||
|
|
||||||
|
<section className="small">
|
||||||
<SubTitle title="Path to kubectl binary" />
|
<SubTitle title="Path to kubectl binary" />
|
||||||
<Input
|
<Input
|
||||||
theme="round-black"
|
theme="round-black"
|
||||||
@ -61,9 +83,7 @@ export const KubectlBinaries = observer(({ preferences }: { preferences: UserPre
|
|||||||
onBlur={save}
|
onBlur={save}
|
||||||
disabled={preferences.downloadKubectlBinaries}
|
disabled={preferences.downloadKubectlBinaries}
|
||||||
/>
|
/>
|
||||||
<small className="hint">
|
</section>
|
||||||
The path to the kubectl binary on the system.
|
|
||||||
</small>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,22 +6,32 @@ import { disposeOnUnmount, observer } from "mobx-react";
|
|||||||
|
|
||||||
import { userStore } from "../../../common/user-store";
|
import { userStore } from "../../../common/user-store";
|
||||||
import { isWindows } from "../../../common/vars";
|
import { isWindows } from "../../../common/vars";
|
||||||
import { appPreferenceRegistry } from "../../../extensions/registries/app-preference-registry";
|
import { appPreferenceRegistry, RegisteredAppPreference } from "../../../extensions/registries/app-preference-registry";
|
||||||
import { themeStore } from "../../theme.store";
|
import { themeStore } from "../../theme.store";
|
||||||
import { Checkbox } from "../checkbox";
|
|
||||||
import { Input } from "../input";
|
import { Input } from "../input";
|
||||||
import { PageLayout } from "../layout/page-layout";
|
import { PageLayout } from "../layout/page-layout";
|
||||||
import { SubTitle } from "../layout/sub-title";
|
import { SubTitle } from "../layout/sub-title";
|
||||||
import { Select, SelectOption } from "../select";
|
import { Select, SelectOption } from "../select";
|
||||||
import { HelmCharts } from "./helm-charts";
|
import { HelmCharts } from "./helm-charts";
|
||||||
import { KubectlBinaries } from "./kubectl-binaries";
|
import { KubectlBinaries } from "./kubectl-binaries";
|
||||||
import { ScrollSpy } from "../scroll-spy/scroll-spy";
|
|
||||||
import { navigation } from "../../navigation";
|
import { navigation } from "../../navigation";
|
||||||
|
import { Tab, Tabs } from "../tabs";
|
||||||
|
import { FormSwitch, Switcher } from "../switch";
|
||||||
|
|
||||||
|
enum Pages {
|
||||||
|
Application = "application",
|
||||||
|
Proxy = "proxy",
|
||||||
|
Kubernetes = "kubernetes",
|
||||||
|
Telemetry = "telemetry",
|
||||||
|
Extensions = "extensions",
|
||||||
|
Other = "other"
|
||||||
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class Preferences extends React.Component {
|
export class Preferences extends React.Component {
|
||||||
@observable httpProxy = userStore.preferences.httpsProxy || "";
|
@observable httpProxy = userStore.preferences.httpsProxy || "";
|
||||||
@observable shell = userStore.preferences.shell || "";
|
@observable shell = userStore.preferences.shell || "";
|
||||||
|
@observable activeTab = Pages.Application;
|
||||||
|
|
||||||
@computed get themeOptions(): SelectOption<string>[] {
|
@computed get themeOptions(): SelectOption<string>[] {
|
||||||
return themeStore.themes.map(theme => ({
|
return themeStore.themes.map(theme => ({
|
||||||
@ -45,9 +55,46 @@ export class Preferences extends React.Component {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onTabChange = (tabId: Pages) => {
|
||||||
|
this.activeTab = tabId;
|
||||||
|
};
|
||||||
|
|
||||||
|
renderNavigation() {
|
||||||
|
const extensions = appPreferenceRegistry.getItems().filter(e => !e.showInPreferencesTab);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tabs className="flex column" scrollable={false} onChange={this.onTabChange} value={this.activeTab}>
|
||||||
|
<div className="header">Preferences</div>
|
||||||
|
<Tab value={Pages.Application} label="Application" data-testid="application-tab"/>
|
||||||
|
<Tab value={Pages.Proxy} label="Proxy" data-testid="proxy-tab"/>
|
||||||
|
<Tab value={Pages.Kubernetes} label="Kubernetes" data-testid="kube-tab"/>
|
||||||
|
<Tab value={Pages.Telemetry} label="Telemetry" data-testid="telemetry-tab"/>
|
||||||
|
{extensions.length > 0 &&
|
||||||
|
<Tab value={Pages.Extensions} label="Extensions" data-testid="extensions-tab"/>
|
||||||
|
}
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderExtension({ title, id, components: { Hint, Input } }: RegisteredAppPreference) {
|
||||||
|
return (
|
||||||
|
<React.Fragment key={id}>
|
||||||
|
<section id={id} className="small">
|
||||||
|
<SubTitle title={title}/>
|
||||||
|
<Input/>
|
||||||
|
<div className="hint">
|
||||||
|
<Hint/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<hr className="small"/>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { preferences } = userStore;
|
const { preferences } = userStore;
|
||||||
const header = <h2>Preferences</h2>;
|
const extensions = appPreferenceRegistry.getItems();
|
||||||
|
const telemetryExtensions = extensions.filter(e => e.showInPreferencesTab == Pages.Telemetry);
|
||||||
let defaultShell = process.env.SHELL || process.env.PTYSHELL;
|
let defaultShell = process.env.SHELL || process.env.PTYSHELL;
|
||||||
|
|
||||||
if (!defaultShell) {
|
if (!defaultShell) {
|
||||||
@ -59,29 +106,59 @@ export class Preferences extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollSpy htmlFor="ScrollSpyRoot" render={navigation => (
|
|
||||||
<PageLayout
|
<PageLayout
|
||||||
showOnTop
|
showOnTop
|
||||||
navigation={navigation}
|
navigation={this.renderNavigation()}
|
||||||
className="Preferences"
|
className="Preferences"
|
||||||
contentGaps={false}
|
contentGaps={false}
|
||||||
header={header}
|
|
||||||
>
|
>
|
||||||
<section id="application" title="Application">
|
{this.activeTab == Pages.Application && (
|
||||||
<section>
|
<section id="application">
|
||||||
<h1>Application</h1>
|
<h2 data-testid="application-header">Application</h2>
|
||||||
</section>
|
|
||||||
<section id="appearance">
|
<section id="appearance">
|
||||||
<h2>Appearance</h2>
|
|
||||||
<SubTitle title="Theme"/>
|
<SubTitle title="Theme"/>
|
||||||
<Select
|
<Select
|
||||||
options={this.themeOptions}
|
options={this.themeOptions}
|
||||||
value={preferences.colorTheme}
|
value={preferences.colorTheme}
|
||||||
onChange={({ value }: SelectOption) => preferences.colorTheme = value}
|
onChange={({ value }: SelectOption) => preferences.colorTheme = value}
|
||||||
|
themeName="lens"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<hr className="small"/>
|
||||||
|
|
||||||
|
<section id="shell" className="small">
|
||||||
|
<SubTitle title="Terminal Shell Path"/>
|
||||||
|
<Input
|
||||||
|
theme="round-black"
|
||||||
|
placeholder={defaultShell}
|
||||||
|
value={this.shell}
|
||||||
|
onChange={v => this.shell = v}
|
||||||
|
onBlur={() => preferences.shell = this.shell}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<section id="other">
|
||||||
|
<SubTitle title="Start-up"/>
|
||||||
|
<FormSwitch
|
||||||
|
control={
|
||||||
|
<Switcher
|
||||||
|
checked={preferences.openAtLogin}
|
||||||
|
onChange={v => preferences.openAtLogin = v.target.checked}
|
||||||
|
name="startup"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Automatically start Lens on login"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
{this.activeTab == Pages.Proxy && (
|
||||||
<section id="proxy">
|
<section id="proxy">
|
||||||
<h2>Proxy</h2>
|
<section>
|
||||||
|
<h2 data-testid="proxy-header">Proxy</h2>
|
||||||
<SubTitle title="HTTP Proxy"/>
|
<SubTitle title="HTTP Proxy"/>
|
||||||
<Input
|
<Input
|
||||||
theme="round-black"
|
theme="round-black"
|
||||||
@ -93,12 +170,21 @@ export class Preferences extends React.Component {
|
|||||||
<small className="hint">
|
<small className="hint">
|
||||||
Proxy is used only for non-cluster communication.
|
Proxy is used only for non-cluster communication.
|
||||||
</small>
|
</small>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<hr className="small"/>
|
||||||
|
|
||||||
|
<section className="small">
|
||||||
<SubTitle title="Certificate Trust"/>
|
<SubTitle title="Certificate Trust"/>
|
||||||
<Checkbox
|
<FormSwitch
|
||||||
|
control={
|
||||||
|
<Switcher
|
||||||
|
checked={preferences.allowUntrustedCAs}
|
||||||
|
onChange={v => preferences.allowUntrustedCAs = v.target.checked}
|
||||||
|
name="startup"
|
||||||
|
/>
|
||||||
|
}
|
||||||
label="Allow untrusted Certificate Authorities"
|
label="Allow untrusted Certificate Authorities"
|
||||||
value={preferences.allowUntrustedCAs}
|
|
||||||
onChange={v => preferences.allowUntrustedCAs = v}
|
|
||||||
/>
|
/>
|
||||||
<small className="hint">
|
<small className="hint">
|
||||||
This will make Lens to trust ANY certificate authority without any validations.{" "}
|
This will make Lens to trust ANY certificate authority without any validations.{" "}
|
||||||
@ -106,63 +192,37 @@ export class Preferences extends React.Component {
|
|||||||
Does not affect cluster communications!
|
Does not affect cluster communications!
|
||||||
</small>
|
</small>
|
||||||
</section>
|
</section>
|
||||||
<section id="shell">
|
|
||||||
<h2>Terminal Shell</h2>
|
|
||||||
<SubTitle title="Shell Path"/>
|
|
||||||
<Input
|
|
||||||
theme="round-black"
|
|
||||||
placeholder={defaultShell}
|
|
||||||
value={this.shell}
|
|
||||||
onChange={v => this.shell = v}
|
|
||||||
onBlur={() => preferences.shell = this.shell}
|
|
||||||
/>
|
|
||||||
<small className="hint">
|
|
||||||
The path of the shell that the terminal uses.
|
|
||||||
</small>
|
|
||||||
</section>
|
|
||||||
<section id="startup">
|
|
||||||
<h2>Start-up</h2>
|
|
||||||
<SubTitle title="Automatic Start-up"/>
|
|
||||||
<Checkbox
|
|
||||||
label="Automatically start Lens on login"
|
|
||||||
value={preferences.openAtLogin}
|
|
||||||
onChange={v => preferences.openAtLogin = v}
|
|
||||||
/>
|
|
||||||
</section>
|
|
||||||
</section>
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.activeTab == Pages.Kubernetes && (
|
||||||
<section id="kubernetes">
|
<section id="kubernetes">
|
||||||
<section>
|
|
||||||
<h1>Kubernetes</h1>
|
|
||||||
</section>
|
|
||||||
<section id="kubectl">
|
<section id="kubectl">
|
||||||
<h2>Kubectl binary</h2>
|
<h2 data-testid="kubernetes-header">Kubernetes</h2>
|
||||||
<KubectlBinaries preferences={preferences}/>
|
<KubectlBinaries preferences={preferences}/>
|
||||||
</section>
|
</section>
|
||||||
|
<hr/>
|
||||||
<section id="helm">
|
<section id="helm">
|
||||||
<h2>Helm Charts</h2>
|
<h2>Helm Charts</h2>
|
||||||
<HelmCharts/>
|
<HelmCharts/>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.activeTab == Pages.Telemetry && (
|
||||||
|
<section id="telemetry">
|
||||||
|
<h2 data-testid="telemetry-header">Telemetry</h2>
|
||||||
|
{telemetryExtensions.map(this.renderExtension)}
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.activeTab == Pages.Extensions && (
|
||||||
<section id="extensions">
|
<section id="extensions">
|
||||||
<section>
|
<h2>Extensions</h2>
|
||||||
<h1>Extensions</h1>
|
{extensions.filter(e => !e.showInPreferencesTab).map(this.renderExtension)}
|
||||||
</section>
|
|
||||||
{appPreferenceRegistry.getItems().map(({ title, id, components: { Hint, Input } }, index) => {
|
|
||||||
return (
|
|
||||||
<section key={index} id={title}>
|
|
||||||
<h2 id={id}>{title}</h2>
|
|
||||||
<Input/>
|
|
||||||
<small className="hint">
|
|
||||||
<Hint/>
|
|
||||||
</small>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</section>
|
</section>
|
||||||
|
)}
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
)}/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,12 +105,6 @@ ol, ul {
|
|||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
|
||||||
margin: $margin 0 !important;
|
|
||||||
height: 1px;
|
|
||||||
background: $grey-800;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
color: $textColorPrimary;
|
color: $textColorPrimary;
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden; // required for transition effect on hover
|
overflow: hidden; // required for transition effect on hover
|
||||||
color: white;
|
color: white;
|
||||||
|
font-family: var(--font-main);
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@ -96,14 +96,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
background: $mainBackground;
|
background: var(--inputControlBackground);
|
||||||
border: 1px solid $borderFaintColor;
|
border: 1px solid var(--inputControlBorder);
|
||||||
border-radius: $radius;
|
border-radius: 4px;
|
||||||
padding: $padding;
|
padding: $padding;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--inputControlHoverBorder);
|
||||||
|
}
|
||||||
|
|
||||||
&:focus-within {
|
&:focus-within {
|
||||||
border: 2px solid $colorInfo;
|
border-color: $colorInfo;
|
||||||
padding: $padding - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
|
|||||||
@ -1,30 +1,22 @@
|
|||||||
.PageLayout {
|
.PageLayout {
|
||||||
--width: 60%;
|
--width: 75%;
|
||||||
--nav-width: 180px;
|
--nav-width: 180px;
|
||||||
--nav-column-width: 30vw;
|
--nav-column-width: 30vw;
|
||||||
--spacing: calc(var(--unit) * 2);
|
|
||||||
--wrapper-padding: calc(var(--spacing) * 2);
|
|
||||||
--header-height: 64px;
|
|
||||||
--header-height-mac: 80px;
|
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: grid !important;
|
display: grid !important;
|
||||||
grid-template-rows: min-content 1fr;
|
|
||||||
grid-template-columns: 1fr;
|
@include media("<1000px") {
|
||||||
|
--width: 85%;
|
||||||
|
}
|
||||||
|
|
||||||
&.showNavigation {
|
&.showNavigation {
|
||||||
--width: 70%;
|
|
||||||
|
|
||||||
grid-template-columns: var(--nav-column-width) 1fr;
|
grid-template-columns: var(--nav-column-width) 1fr;
|
||||||
|
|
||||||
> .content-wrapper {
|
> .contentRegion {
|
||||||
> .content {
|
justify-content: flex-start;
|
||||||
width: 100%;
|
|
||||||
padding-left: 1px; // Fix visual content crop
|
|
||||||
padding-right: calc(var(--nav-column-width) - var(--nav-width));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,96 +27,172 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 24px;
|
bottom: 0;
|
||||||
height: unset;
|
height: unset;
|
||||||
background-color: var(--mainBackground);
|
background-color: var(--settingsBackground);
|
||||||
|
|
||||||
// adds extra space for traffic-light top buttons (mac only)
|
|
||||||
.is-mac & > .header {
|
|
||||||
height: var(--header-height-mac);
|
|
||||||
padding-top: calc(var(--spacing) * 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> .header {
|
> .sidebarRegion {
|
||||||
position: sticky;
|
|
||||||
padding: var(--spacing);
|
|
||||||
background-color: var(--layoutTabsBackground);
|
|
||||||
height: var(--header-height);
|
|
||||||
grid-column-start: 1;
|
|
||||||
grid-column-end: 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .content-navigation {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
margin-top: 32px;
|
background-color: var(--secondaryBackground);
|
||||||
|
|
||||||
ul.TreeView {
|
.sidebar {
|
||||||
width: var(--nav-width);
|
width: 218px;
|
||||||
padding-right: 24px;
|
padding: 60px 10px 60px 20px;
|
||||||
|
|
||||||
|
.Tabs {
|
||||||
|
.header {
|
||||||
|
padding: 6px 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 16px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .content-wrapper {
|
.Tab {
|
||||||
padding: 32px;
|
padding: 6px 10px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
border-radius: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--textColorSecondary);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--navHoverBackground);
|
||||||
|
color: var(--navHoverColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: var(--navSelectedBackground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .contentRegion {
|
||||||
|
display: flex;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
> .content {
|
> .content {
|
||||||
width: var(--width);
|
width: var(--width);
|
||||||
margin: 0 auto;
|
padding: 60px 40px 80px;
|
||||||
|
|
||||||
|
> section {
|
||||||
|
&:last-of-type {
|
||||||
|
margin-bottom: 80px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
> .toolsRegion {
|
||||||
line-height: 140%;
|
.fixedTools {
|
||||||
|
position: fixed;
|
||||||
|
top: 60px;
|
||||||
|
|
||||||
|
.closeBtn {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
border: 2px solid var(--textColorDimmed);
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #72767d4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Icon {
|
||||||
|
color: var(--textColorSecondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.esc {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 4px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--textColorDimmed);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--colorInfo);
|
color: var(--colorInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
.SubTitle {
|
|
||||||
text-transform: none;
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Select {
|
|
||||||
&__control {
|
|
||||||
box-shadow: 0 0 0 1px var(--borderFaintColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
section {
|
section {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-bottom: var(--spacing);
|
|
||||||
|
|
||||||
> :not(:last-child) {
|
&:not(:first-of-type) {
|
||||||
margin-bottom: var(--spacing);
|
margin-top: 40px;
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2 {
|
h1, h2 {
|
||||||
color: var(--textColorAccent);
|
color: var(--textColorAccent);
|
||||||
}
|
text-transform: uppercase;
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: x-large;
|
|
||||||
border-bottom: 1px solid var(--borderFaintColor);
|
|
||||||
padding-bottom: var(--padding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: large;
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
small.hint {
|
.hint {
|
||||||
margin-top: calc(var(--unit) * -1.5);
|
margin-top: 8px;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.SubTitle {
|
.SubTitle {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin-top: 40px;
|
||||||
|
height: 1px;
|
||||||
|
border-top: thin solid var(--hrColor);
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,19 +3,18 @@ import "./page-layout.scss";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { autobind, cssNames, IClassName } from "../../utils";
|
import { autobind, cssNames, IClassName } from "../../utils";
|
||||||
import { Icon } from "../icon";
|
|
||||||
import { navigation } from "../../navigation";
|
import { navigation } from "../../navigation";
|
||||||
import { NavigationTree, RecursiveTreeView } from "../tree-view";
|
import { Icon } from "../icon";
|
||||||
|
|
||||||
export interface PageLayoutProps extends React.DOMAttributes<any> {
|
export interface PageLayoutProps extends React.DOMAttributes<any> {
|
||||||
className?: IClassName;
|
className?: IClassName;
|
||||||
header: React.ReactNode;
|
header?: React.ReactNode;
|
||||||
headerClass?: IClassName;
|
headerClass?: IClassName;
|
||||||
contentClass?: IClassName;
|
contentClass?: IClassName;
|
||||||
provideBackButtonNavigation?: boolean;
|
provideBackButtonNavigation?: boolean;
|
||||||
contentGaps?: boolean;
|
contentGaps?: boolean;
|
||||||
showOnTop?: boolean; // covers whole app view
|
showOnTop?: boolean; // covers whole app view
|
||||||
navigation?: NavigationTree[];
|
navigation?: React.ReactNode;
|
||||||
back?: (evt: React.MouseEvent | KeyboardEvent) => void;
|
back?: (evt: React.MouseEvent | KeyboardEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,32 +57,34 @@ export class PageLayout extends React.Component<PageLayoutProps> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
contentClass, header, headerClass, provideBackButtonNavigation,
|
contentClass, headerClass, provideBackButtonNavigation,
|
||||||
contentGaps, showOnTop, navigation, children, ...elemProps
|
contentGaps, showOnTop, navigation, children, ...elemProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const className = cssNames("PageLayout", { showOnTop, showNavigation: navigation }, this.props.className);
|
const className = cssNames("PageLayout", { showOnTop, showNavigation: navigation }, this.props.className);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div {...elemProps} className={className}>
|
<div {...elemProps} className={className}>
|
||||||
<div className={cssNames("header flex gaps align-center", headerClass)}>
|
|
||||||
{header}
|
|
||||||
{provideBackButtonNavigation && (
|
|
||||||
<Icon
|
|
||||||
big material="close"
|
|
||||||
className="back box right"
|
|
||||||
onClick={this.back}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{ navigation && (
|
{ navigation && (
|
||||||
<nav className="content-navigation">
|
<nav className="sidebarRegion">
|
||||||
<RecursiveTreeView data={navigation}/>
|
<div className="sidebar">
|
||||||
|
{navigation}
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
)}
|
)}
|
||||||
<div className="content-wrapper" id="ScrollSpyRoot">
|
<div className="contentRegion" id="ScrollSpyRoot">
|
||||||
<div className={cssNames("content", contentClass, contentGaps && "flex column gaps")}>
|
<div className={cssNames("content", contentClass, contentGaps && "flex column gaps")}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="toolsRegion">
|
||||||
|
<div className="fixedTools">
|
||||||
|
<div className="closeBtn" role="button" aria-label="Close" onClick={this.back}>
|
||||||
|
<Icon material="close"/>
|
||||||
|
</div>
|
||||||
|
<div className="esc" aria-hidden="true">
|
||||||
|
ESC
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -6,7 +6,7 @@ html {
|
|||||||
|
|
||||||
--select-menu-bgc: #{$menuBackgroundColor};
|
--select-menu-bgc: #{$menuBackgroundColor};
|
||||||
--select-menu-border-color: #{$halfGray};
|
--select-menu-border-color: #{$halfGray};
|
||||||
--select-option-selected-color: #{$selectOptionHoveredColor};
|
--select-option-selected-color: #{$inputOptionHoverColor};
|
||||||
--select-option-focused-bgc: #{$colorInfo};
|
--select-option-focused-bgc: #{$colorInfo};
|
||||||
--select-option-focused-color: #{$textColorAccent};
|
--select-option-focused-color: #{$textColorAccent};
|
||||||
|
|
||||||
@ -14,6 +14,8 @@ html {
|
|||||||
position: relative;
|
position: relative;
|
||||||
min-width: 220px;
|
min-width: 220px;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
@ -33,7 +35,7 @@ html {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&--is-focused {
|
&--is-focused {
|
||||||
box-shadow: 0 0 0 2px $primary;
|
box-shadow: 0 0 0 1px $primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,8 +75,7 @@ html {
|
|||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
|
|
||||||
&-list {
|
&-list {
|
||||||
padding-right: 1px;
|
padding: 6px;
|
||||||
padding-left: 1px;
|
|
||||||
width: max-content;
|
width: max-content;
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
}
|
}
|
||||||
@ -183,5 +184,54 @@ html {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.theme-lens {
|
||||||
|
:hover {
|
||||||
|
&.Select__control {
|
||||||
|
box-shadow: 0 0 0 1px var(--inputControlHoverBorder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:focus-within {
|
||||||
|
&.Select__control {
|
||||||
|
box-shadow: 0 0 0 1px $colorInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Select__menu {
|
||||||
|
box-shadow: inset 0 0 0 1px var(--inputControlBorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Select {
|
||||||
|
&__control {
|
||||||
|
box-shadow: 0 0 0 1px var(--inputControlBorder);
|
||||||
|
background: var(--inputControlBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__menu {
|
||||||
|
&-list {
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__option {
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: var(--inputControlBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--is-selected {
|
||||||
|
background: var(--inputControlBackground);
|
||||||
|
color: var(--textColorAccent);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--is-focused {
|
||||||
|
color: var(--textColorPrimary);
|
||||||
|
background: var(--inputControlBackground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ export interface SelectOption<T = any> {
|
|||||||
|
|
||||||
export interface SelectProps<T = any> extends ReactSelectProps<T>, CreatableProps<T> {
|
export interface SelectProps<T = any> extends ReactSelectProps<T>, CreatableProps<T> {
|
||||||
value?: T;
|
value?: T;
|
||||||
themeName?: "dark" | "light" | "outlined";
|
themeName?: "dark" | "light" | "outlined" | "lens";
|
||||||
menuClass?: string;
|
menuClass?: string;
|
||||||
isCreatable?: boolean;
|
isCreatable?: boolean;
|
||||||
autoConvertOptions?: boolean; // to internal format (i.e. {value: T, label: string}[]), not working with groups
|
autoConvertOptions?: boolean; // to internal format (i.e. {value: T, label: string}[]), not working with groups
|
||||||
|
|||||||
28
src/renderer/components/switch/form-switcher.tsx
Normal file
28
src/renderer/components/switch/form-switcher.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import React from "react";
|
||||||
|
import FormControlLabel, { FormControlLabelProps } from "@material-ui/core/FormControlLabel";
|
||||||
|
import { makeStyles } from "@material-ui/styles";
|
||||||
|
|
||||||
|
const useStyles = makeStyles({
|
||||||
|
root: {
|
||||||
|
margin: 0,
|
||||||
|
"& .MuiTypography-root": {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: 500,
|
||||||
|
flex: 1,
|
||||||
|
color: "var(--textColorAccent)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export function FormSwitch(props: FormControlLabelProps) {
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControlLabel
|
||||||
|
control={props.control}
|
||||||
|
labelPlacement="start"
|
||||||
|
label={props.label}
|
||||||
|
className={classes.root}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
2
src/renderer/components/switch/index.ts
Normal file
2
src/renderer/components/switch/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./switcher";
|
||||||
|
export * from "./form-switcher";
|
||||||
68
src/renderer/components/switch/switcher.tsx
Normal file
68
src/renderer/components/switch/switcher.tsx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { createStyles, withStyles, Theme } from "@material-ui/core/styles";
|
||||||
|
import Switch, { SwitchClassKey, SwitchProps } from "@material-ui/core/Switch";
|
||||||
|
|
||||||
|
interface Styles extends Partial<Record<SwitchClassKey, string>> {
|
||||||
|
focusVisible?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props extends SwitchProps {
|
||||||
|
classes: Styles;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Switcher = withStyles((theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
root: {
|
||||||
|
width: 40,
|
||||||
|
height: 24,
|
||||||
|
padding: 0,
|
||||||
|
margin: "0 0 0 8px",
|
||||||
|
},
|
||||||
|
switchBase: {
|
||||||
|
padding: 1,
|
||||||
|
paddingLeft: 4,
|
||||||
|
"&$checked": {
|
||||||
|
transform: "translateX(14px)",
|
||||||
|
color: "white",
|
||||||
|
"& + $track": {
|
||||||
|
backgroundColor: "#52d869",
|
||||||
|
opacity: 1,
|
||||||
|
border: "none",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"&$focusVisible $thumb": {
|
||||||
|
color: "#52d869",
|
||||||
|
border: "6px solid #fff",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
thumb: {
|
||||||
|
width: 18,
|
||||||
|
height: 18,
|
||||||
|
marginTop: 2,
|
||||||
|
boxShadow: "none"
|
||||||
|
},
|
||||||
|
track: {
|
||||||
|
borderRadius: 26 / 2,
|
||||||
|
backgroundColor: "#72767b",
|
||||||
|
opacity: 1,
|
||||||
|
transition: theme.transitions.create(["background-color", "border"]),
|
||||||
|
},
|
||||||
|
checked: {},
|
||||||
|
focusVisible: {},
|
||||||
|
}),
|
||||||
|
)(({ classes, ...props }: Props) => {
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
focusVisibleClassName={classes.focusVisible}
|
||||||
|
disableRipple
|
||||||
|
classes={{
|
||||||
|
root: classes.root,
|
||||||
|
switchBase: classes.switchBase,
|
||||||
|
thumb: classes.thumb,
|
||||||
|
track: classes.track,
|
||||||
|
checked: classes.checked,
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
@ -9,12 +9,14 @@
|
|||||||
"golden": "#ffc63d",
|
"golden": "#ffc63d",
|
||||||
"halfGray": "#87909c80",
|
"halfGray": "#87909c80",
|
||||||
"primary": "#3d90ce",
|
"primary": "#3d90ce",
|
||||||
"textColorPrimary": "#87909c",
|
"textColorPrimary": "#8e9297",
|
||||||
"textColorSecondary": "#a0a0a0",
|
"textColorSecondary": "#a0a0a0",
|
||||||
"textColorAccent": "#ffffff",
|
"textColorAccent": "#ffffff",
|
||||||
|
"textColorDimmed": "#8e92978c",
|
||||||
"borderColor": "#4c5053",
|
"borderColor": "#4c5053",
|
||||||
"borderFaintColor": "#373a3e",
|
"borderFaintColor": "#373a3e",
|
||||||
"mainBackground": "#1e2124",
|
"mainBackground": "#1e2124",
|
||||||
|
"secondaryBackground": "#212427",
|
||||||
"contentColor": "#262b2f",
|
"contentColor": "#262b2f",
|
||||||
"layoutBackground": "#2e3136",
|
"layoutBackground": "#2e3136",
|
||||||
"layoutTabsBackground": "#252729",
|
"layoutTabsBackground": "#252729",
|
||||||
@ -112,11 +114,19 @@
|
|||||||
"chartStripesColor": "#ffffff08",
|
"chartStripesColor": "#ffffff08",
|
||||||
"chartCapacityColor": "#4c545f",
|
"chartCapacityColor": "#4c545f",
|
||||||
"pieChartDefaultColor": "#30353a",
|
"pieChartDefaultColor": "#30353a",
|
||||||
"selectOptionHoveredColor": "#87909c",
|
"inputOptionHoverColor": "#87909c",
|
||||||
|
"inputControlBackground": "#00000021",
|
||||||
|
"inputControlBorder": "#202225bf",
|
||||||
|
"inputControlHoverBorder": "#07080880",
|
||||||
"lineProgressBackground": "#414448",
|
"lineProgressBackground": "#414448",
|
||||||
"radioActiveBackground": "#36393e",
|
"radioActiveBackground": "#36393e",
|
||||||
"menuActiveBackground": "#36393e",
|
"menuActiveBackground": "#36393e",
|
||||||
"menuSelectedOptionBgc": "#36393e",
|
"menuSelectedOptionBgc": "#36393e",
|
||||||
"scrollBarColor": "#5f6064"
|
"scrollBarColor": "#5f6064",
|
||||||
|
"settingsBackground": "#2b3035",
|
||||||
|
"navSelectedBackground": "#4f545c52",
|
||||||
|
"navHoverBackground": "#4f545c29",
|
||||||
|
"navHoverColor": "#dcddde",
|
||||||
|
"hrColor": "#ffffff0f"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,9 +12,11 @@
|
|||||||
"textColorPrimary": "#555555",
|
"textColorPrimary": "#555555",
|
||||||
"textColorSecondary": "#51575d",
|
"textColorSecondary": "#51575d",
|
||||||
"textColorAccent": "#333333",
|
"textColorAccent": "#333333",
|
||||||
|
"textColorDimmed": "#5557598c",
|
||||||
"borderColor": "#c9cfd3",
|
"borderColor": "#c9cfd3",
|
||||||
"borderFaintColor": "#dfdfdf",
|
"borderFaintColor": "#dfdfdf",
|
||||||
"mainBackground": "#f1f1f1",
|
"mainBackground": "#f1f1f1",
|
||||||
|
"secondaryBackground": "#f2f3f5",
|
||||||
"contentColor": "#ffffff",
|
"contentColor": "#ffffff",
|
||||||
"layoutBackground": "#e8e8e8",
|
"layoutBackground": "#e8e8e8",
|
||||||
"layoutTabsBackground": "#f8f8f8",
|
"layoutTabsBackground": "#f8f8f8",
|
||||||
@ -113,12 +115,20 @@
|
|||||||
"chartStripesColor": "#00000009",
|
"chartStripesColor": "#00000009",
|
||||||
"chartCapacityColor": "#cccccc",
|
"chartCapacityColor": "#cccccc",
|
||||||
"pieChartDefaultColor": "#efefef",
|
"pieChartDefaultColor": "#efefef",
|
||||||
"selectOptionHoveredColor": "#ffffff",
|
"inputOptionHoverColor": "#ffffff",
|
||||||
|
"inputControlBackground": "#f6f6f7",
|
||||||
|
"inputControlBorder": "#cccdcf",
|
||||||
|
"inputControlHoverBorder": "#b9bbbe",
|
||||||
"lineProgressBackground": "#e8e8e8",
|
"lineProgressBackground": "#e8e8e8",
|
||||||
"radioActiveBackground": "#f1f1f1",
|
"radioActiveBackground": "#f1f1f1",
|
||||||
"menuActiveBackground": "#e8e8e8",
|
"menuActiveBackground": "#e8e8e8",
|
||||||
"menuSelectedOptionBgc": "#e8e8e8",
|
"menuSelectedOptionBgc": "#e8e8e8",
|
||||||
"scrollBarColor": "#bbbbbb",
|
"scrollBarColor": "#bbbbbb",
|
||||||
"canvasBackground": "#24292e"
|
"canvasBackground": "#24292e",
|
||||||
|
"settingsBackground": "#ffffff",
|
||||||
|
"navSelectedBackground": "#747f8d3d",
|
||||||
|
"navHoverBackground": "#747f8d14",
|
||||||
|
"navHoverColor": "#2e3135",
|
||||||
|
"hrColor": "#06060714"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -128,7 +128,7 @@ $iconActiveColor: var(--iconActiveColor);
|
|||||||
$iconActiveBackground: var(--iconActiveBackground);
|
$iconActiveBackground: var(--iconActiveBackground);
|
||||||
$filterAreaBackground: var(--filterAreaBackground);
|
$filterAreaBackground: var(--filterAreaBackground);
|
||||||
|
|
||||||
$selectOptionHoveredColor: var(--selectOptionHoveredColor);
|
$inputOptionHoverColor: var(--inputOptionHoverColor);
|
||||||
$lineProgressBackground: var(--lineProgressBackground);
|
$lineProgressBackground: var(--lineProgressBackground);
|
||||||
$radioActiveBackground: var(--radioActiveBackground);
|
$radioActiveBackground: var(--radioActiveBackground);
|
||||||
$menuActiveBackground: var(--menuActiveBackground);
|
$menuActiveBackground: var(--menuActiveBackground);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user