mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-01 19:15:52 +01:00
Add experimental high contrast mode (#1845)
Add an experimental high contrast color theme to SCM-Manager. The high contrast mode uses a dark background and color with a high contrast for a better accessibility. The change adds the theme to ui-styles and theme switcher to the storybook of ui-components.
This commit is contained in:
2
gradle/changelog/highcontrast.yaml
Normal file
2
gradle/changelog/highcontrast.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- type: added
|
||||
descripion: Experimental high contrast mode ([#1845](https://github.com/scm-manager/scm-manager/pull/1845))
|
||||
46
scm-ui/ui-components/.storybook/RemoveThemesPlugin.js
Normal file
46
scm-ui/ui-components/.storybook/RemoveThemesPlugin.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
class RemoveThemesPlugin {
|
||||
apply (compiler) {
|
||||
compiler.hooks.compilation.tap('RemoveThemesPlugin', (compilation) => {
|
||||
|
||||
HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration.tapAsync(
|
||||
'RemoveThemesPlugin',
|
||||
(data, cb) => {
|
||||
if (data.assets.css) {
|
||||
data.assets.css = data.assets.css.filter(css => css.startsWith("ui-theme-"))
|
||||
}
|
||||
data.assets.css = [];
|
||||
// Tell webpack to move on
|
||||
cb(null, data)
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RemoveThemesPlugin
|
||||
80
scm-ui/ui-components/.storybook/main.js
Normal file
80
scm-ui/ui-components/.storybook/main.js
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const RemoveThemesPlugin = require("./RemoveThemesPlugin");
|
||||
const WorkerPlugin = require("worker-plugin");
|
||||
|
||||
const root = path.resolve("..");
|
||||
|
||||
const themedir = path.join(root, "ui-styles", "src");
|
||||
|
||||
const themes = fs
|
||||
.readdirSync(themedir)
|
||||
.map((filename) => path.parse(filename))
|
||||
.filter((p) => p.ext === ".scss")
|
||||
.reduce((entries, current) => ({ ...entries, [current.name]: path.join(themedir, current.base) }), {});
|
||||
|
||||
module.exports = {
|
||||
stories: ["../src/**/*.stories.tsx"],
|
||||
addons: ["storybook-addon-i18next", "storybook-addon-themes"],
|
||||
webpackFinal: async (config) => {
|
||||
// add our themes to webpack entry points
|
||||
config.entry = {
|
||||
main: config.entry,
|
||||
...themes,
|
||||
};
|
||||
|
||||
// fix usage of web workers
|
||||
// required for diff with syntax highlighting
|
||||
config.plugins.push(new WorkerPlugin());
|
||||
|
||||
// create separate css files for our themes
|
||||
config.plugins.push(
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "ui-theme-[name].css",
|
||||
ignoreOrder: false
|
||||
}),
|
||||
);
|
||||
|
||||
config.module.rules.push({
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
"css-loader",
|
||||
"sass-loader",
|
||||
],
|
||||
});
|
||||
|
||||
// the html-webpack-plugin adds the generated css to iframe,
|
||||
// which overrides our manually loaded css files.
|
||||
// So we use a custom plugin which uses a hook of html-webpack-plugin
|
||||
// to filter our themes from the output.
|
||||
config.plugins.push(new RemoveThemesPlugin());
|
||||
|
||||
return config;
|
||||
},
|
||||
};
|
||||
26
scm-ui/ui-components/.storybook/preview-head.html
Normal file
26
scm-ui/ui-components/.storybook/preview-head.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-->
|
||||
<link id="ui-theme" data-theme="light" rel="stylesheet" type="text/css" href="/ui-theme-light.css">
|
||||
@@ -23,11 +23,10 @@
|
||||
*/
|
||||
import i18next from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import { addDecorator, configure } from "@storybook/react";
|
||||
import { withI18next } from "storybook-addon-i18next";
|
||||
import "!style-loader!css-loader!sass-loader!../../ui-styles/src/scm.scss";
|
||||
import React from "react";
|
||||
import React, {useEffect} from "react";
|
||||
import withApiProvider from "./withApiProvider";
|
||||
import { withThemes } from 'storybook-addon-themes/react';
|
||||
|
||||
let i18n = i18next;
|
||||
|
||||
@@ -43,30 +42,52 @@ i18n.use(initReactI18next).init({
|
||||
lng: "en",
|
||||
fallbackLng: "en",
|
||||
interpolation: {
|
||||
escapeValue: false
|
||||
escapeValue: false,
|
||||
},
|
||||
react: {
|
||||
useSuspense: false
|
||||
useSuspense: false,
|
||||
},
|
||||
backend: {
|
||||
loadPath: "/locales/{{lng}}/{{ns}}.json",
|
||||
init: {
|
||||
credentials: "same-origin"
|
||||
}
|
||||
}
|
||||
credentials: "same-origin",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
addDecorator(
|
||||
export const decorators = [
|
||||
withI18next({
|
||||
i18n,
|
||||
languages: {
|
||||
en: "English",
|
||||
de: "Deutsch",
|
||||
es: "Spanisch"
|
||||
es: "Spanisch",
|
||||
},
|
||||
}),
|
||||
withApiProvider,
|
||||
withThemes
|
||||
];
|
||||
|
||||
const Decorator = ({children, themeName}) => {
|
||||
useEffect(() => {
|
||||
const link = document.querySelector("#ui-theme");
|
||||
if (link && link["data-theme"] !== themeName) {
|
||||
link.href = `/ui-theme-${themeName}.css`;
|
||||
link["data-theme"] = themeName;
|
||||
}
|
||||
})
|
||||
);
|
||||
}, [themeName]);
|
||||
return <>{children}</>
|
||||
};
|
||||
|
||||
addDecorator(withApiProvider);
|
||||
|
||||
configure(require.context("../src", true, /\.stories\.tsx?$/), module);
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
themes: {
|
||||
Decorator,
|
||||
clearable: false,
|
||||
default: "light",
|
||||
list: [
|
||||
{ name: "light", color: "#fff" },
|
||||
{ name: "highcontrast", color: "#000" },
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -26,9 +26,9 @@
|
||||
"@scm-manager/prettier-config": "^2.10.1",
|
||||
"@scm-manager/tsconfig": "^2.12.0",
|
||||
"@scm-manager/ui-tests": "^2.25.1-SNAPSHOT",
|
||||
"@storybook/addon-actions": "^6.1.17",
|
||||
"@storybook/addon-storyshots": "^6.1.17",
|
||||
"@storybook/react": "^6.1.17",
|
||||
"@storybook/addon-actions": "^6.3.12",
|
||||
"@storybook/addon-storyshots": "^6.3.12",
|
||||
"@storybook/react": "^6.3.12",
|
||||
"@types/classnames": "^2.2.9",
|
||||
"@types/css": "^0.0.31",
|
||||
"@types/enzyme": "^3.10.3",
|
||||
@@ -52,9 +52,11 @@
|
||||
"fetch-mock": "^7.5.1",
|
||||
"gitdiff-parser": "^0.1.2",
|
||||
"i18next-fetch-backend": "^2.2.0",
|
||||
"mini-css-extract-plugin": "^1.6.2",
|
||||
"raf": "^3.4.0",
|
||||
"react-test-renderer": "^17.0.1",
|
||||
"storybook-addon-i18next": "^1.3.0",
|
||||
"storybook-addon-themes": "^6.1.0",
|
||||
"to-camel-case": "^1.0.0",
|
||||
"worker-plugin": "^3.2.0"
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import React, { ReactNode } from "react";
|
||||
import React, { ReactElement, ReactNode } from "react";
|
||||
import Button from "./Button";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import styled from "styled-components";
|
||||
@@ -31,7 +31,6 @@ import DeleteButton from "./DeleteButton";
|
||||
import DownloadButton from "./DownloadButton";
|
||||
import EditButton from "./EditButton";
|
||||
import SubmitButton from "./SubmitButton";
|
||||
import { ReactElement } from "react";
|
||||
import { MemoryRouter } from "react-router-dom";
|
||||
|
||||
const colors = ["primary", "link", "info", "success", "warning", "danger", "white", "light", "dark", "black", "text"];
|
||||
@@ -43,7 +42,7 @@ const Spacing = styled.div`
|
||||
const SpacingDecorator = (story: () => ReactNode) => <Spacing>{story()}</Spacing>;
|
||||
const RoutingDecorator = (story: () => ReactNode) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>;
|
||||
|
||||
storiesOf("Buttons|Button", module)
|
||||
storiesOf("Buttons/Button", module)
|
||||
.addDecorator(RoutingDecorator)
|
||||
.add("Colors", () => (
|
||||
<div>
|
||||
@@ -72,7 +71,7 @@ storiesOf("Buttons|Button", module)
|
||||
));
|
||||
|
||||
const buttonStory = (name: string, storyFn: () => ReactElement) => {
|
||||
return storiesOf("Buttons|" + name, module)
|
||||
return storiesOf("Buttons/" + name, module)
|
||||
.addDecorator(RoutingDecorator)
|
||||
.addDecorator(SpacingDecorator)
|
||||
.add("Default", storyFn);
|
||||
|
||||
@@ -26,7 +26,7 @@ import { MemoryRouter } from "react-router-dom";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import AddKeyValueEntryToTableField from "./AddKeyValueEntryToTableField";
|
||||
|
||||
storiesOf("Forms|AddKeyValueEntryToTableField", module)
|
||||
storiesOf("Forms/AddKeyValueEntryToTableField", module)
|
||||
.addDecorator((story) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
||||
.add("Default", () => (
|
||||
<div className="m-6">
|
||||
|
||||
@@ -105,7 +105,7 @@ const LegacyEvents: FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf("Forms|Checkbox", module)
|
||||
storiesOf("Forms/Checkbox", module)
|
||||
.addDecorator(storyFn => <MemoryRouter>{storyFn()}</MemoryRouter>)
|
||||
.add("Default", () => (
|
||||
<Spacing>
|
||||
|
||||
@@ -25,7 +25,7 @@ import React from "react";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import DropDown from "./DropDown";
|
||||
|
||||
storiesOf("Forms|DropDown", module)
|
||||
storiesOf("Forms/DropDown", module)
|
||||
.add("Default", () => (
|
||||
<DropDown
|
||||
options={["en", "de", "es"]}
|
||||
|
||||
@@ -63,7 +63,7 @@ const ReactHookForm: FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf("Forms|FileInput", module)
|
||||
storiesOf("Forms/FileInput", module)
|
||||
.addDecorator((storyFn) => <Decorator>{storyFn()}</Decorator>)
|
||||
.addDecorator((storyFn) => <MemoryRouter>{storyFn()}</MemoryRouter>)
|
||||
.add("Default", () => <ReactHookForm />);
|
||||
|
||||
@@ -127,7 +127,7 @@ const LegacyEvents: FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf("Forms|InputField", module)
|
||||
storiesOf("Forms/InputField", module)
|
||||
.addDecorator((storyFn) => <Decorator>{storyFn()}</Decorator>)
|
||||
.addDecorator((storyFn) => <MemoryRouter>{storyFn()}</MemoryRouter>)
|
||||
.add("AutoFocus", () => <InputField label="Field with AutoFocus" autofocus={true} />)
|
||||
|
||||
@@ -112,7 +112,7 @@ const LegacyEvents: FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf("Forms|Radio", module)
|
||||
storiesOf("Forms/Radio", module)
|
||||
.addDecorator(storyFn => <MemoryRouter>{storyFn()}</MemoryRouter>)
|
||||
.add("Default", () => (
|
||||
<Spacing>
|
||||
|
||||
@@ -198,7 +198,7 @@ const PreselectOption: FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf("Forms|Select", module)
|
||||
storiesOf("Forms/Select", module)
|
||||
.addDecorator((storyFn) => <MemoryRouter>{storyFn()}</MemoryRouter>)
|
||||
.add("Add no existing value", () => <AddNoExistingValue />)
|
||||
.add("Ref", () => <Ref />)
|
||||
|
||||
@@ -170,7 +170,7 @@ const LegacyEvents: FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf("Forms|Textarea", module)
|
||||
storiesOf("Forms/Textarea", module)
|
||||
.addDecorator((storyFn) => <MemoryRouter>{storyFn()}</MemoryRouter>)
|
||||
.add("OnChange", () => <OnChangeTextarea />)
|
||||
.add("OnSubmit", () => <OnSubmitTextare />)
|
||||
|
||||
@@ -64,7 +64,7 @@ const withBinder = (binder: Binder) => {
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf("Layout|Footer", module)
|
||||
storiesOf("Footer", module)
|
||||
.addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
||||
.add("Default", () => {
|
||||
return <Footer me={trillian} version="2.0.0" links={{}} />;
|
||||
|
||||
@@ -44,7 +44,7 @@ const buttons = [
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf("Modal|ConfirmAlert", module)
|
||||
storiesOf("Modal/ConfirmAlert", module)
|
||||
.addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
||||
.add("Default", () => <ConfirmAlert message={body} title={"Are you sure about that?"} buttons={buttons} />)
|
||||
.add("WithButton", () => {
|
||||
|
||||
@@ -71,7 +71,7 @@ const withFormElementsFooter = (
|
||||
</ButtonGroup>
|
||||
);
|
||||
|
||||
storiesOf("Modal|Modal", module)
|
||||
storiesOf("Modal/Modal", module)
|
||||
.addDecorator((story) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
||||
.add("Default", () => (
|
||||
<NonCloseableModal>
|
||||
|
||||
@@ -52,7 +52,7 @@ const withRoute = (route: string) => {
|
||||
return (story: ReactElement<any>) => <MemoryRouter initialEntries={[route]}>{story}</MemoryRouter>;
|
||||
};
|
||||
|
||||
storiesOf("Navigation|Secondary", module)
|
||||
storiesOf("Secondary Navigation", module)
|
||||
.addDecorator(story => <StateMenuContextProvider>{story()}</StateMenuContextProvider>)
|
||||
.addDecorator(story => (
|
||||
<Columns className="columns">
|
||||
|
||||
@@ -85,7 +85,7 @@ const fileControlFactory: (changeset: Changeset) => FileControlFactory = (change
|
||||
return links.map(({ url, label }) => <JumpToFileButton tooltip={label} link={url} />);
|
||||
};
|
||||
|
||||
storiesOf("Diff", module)
|
||||
storiesOf("Repositories/Diff", module)
|
||||
.addDecorator(RoutingDecorator)
|
||||
.addDecorator((storyFn) => <Container>{storyFn()}</Container>)
|
||||
.add("Default", () => <Diff diff={diffFiles} />)
|
||||
|
||||
@@ -98,7 +98,7 @@ const archivedExportingRepository = {
|
||||
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
|
||||
};
|
||||
|
||||
storiesOf("RepositoryEntry", module)
|
||||
storiesOf("Repositories/RepositoryEntry", module)
|
||||
.addDecorator((story) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
||||
.addDecorator((storyFn) => <Container>{storyFn()}</Container>)
|
||||
.add("Default", () => {
|
||||
|
||||
@@ -164,7 +164,7 @@ const Robohash: FC = ({ children }) => {
|
||||
return <BinderContext.Provider value={binder}>{children}</BinderContext.Provider>;
|
||||
};
|
||||
|
||||
storiesOf("Annotate", module)
|
||||
storiesOf("Repositories/Annotate", module)
|
||||
.addDecorator(storyFn => <MemoryRouter initialEntries={["/"]}>{storyFn()}</MemoryRouter>)
|
||||
.addDecorator(storyFn => <Wrapper className="box">{storyFn()}</Wrapper>)
|
||||
.add("Default", () => (
|
||||
|
||||
@@ -71,7 +71,7 @@ function copy<T>(input: T): T {
|
||||
return JSON.parse(JSON.stringify(input));
|
||||
}
|
||||
|
||||
storiesOf("Changesets", module)
|
||||
storiesOf("Repositories/Changesets", module)
|
||||
.addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
||||
.addDecorator(storyFn => <Wrapper className="box box-link-shadow">{storyFn()}</Wrapper>)
|
||||
.add("Default", () => <ChangesetRow repository={repository} changeset={three}/>)
|
||||
|
||||
@@ -43,10 +43,10 @@
|
||||
|
||||
pre[class*="language-"],
|
||||
code[class*="language-"] {
|
||||
color: #363636;
|
||||
color: var(--sh-base-color);
|
||||
font-size: 1rem;
|
||||
text-shadow: none;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
font-family: var(--sh-font-family);
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
@@ -67,7 +67,7 @@ code[class*="language-"]::selection,
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #7fe3cd;
|
||||
background: var(--sh-selected-color);
|
||||
}
|
||||
|
||||
@media print {
|
||||
@@ -83,14 +83,14 @@ pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
background: #ffffff;
|
||||
background: var(--sh-block-background);
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"] {
|
||||
padding: .1em .3em;
|
||||
border-radius: .3em;
|
||||
color: #ff3860;
|
||||
background: #fbe7eb;
|
||||
color: var(--sh-inline-code-color);
|
||||
background: var(--sh-inline-code-background);
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
@@ -105,11 +105,11 @@ pre[class*="language-"] {
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: #9a9a9a;
|
||||
color: var(--sh-comment-color);
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #9a9a9a;
|
||||
color: var(--sh-punctuation-color);
|
||||
}
|
||||
|
||||
.token.property,
|
||||
@@ -119,7 +119,7 @@ pre[class*="language-"] {
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #2c99c7;
|
||||
color: var(--sh-property-color);
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
@@ -128,7 +128,7 @@ pre[class*="language-"] {
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #005f9a;
|
||||
color: var(--sh-selector-color);
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
@@ -136,23 +136,24 @@ pre[class*="language-"] {
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #686868;
|
||||
color: var(--sh-operator-color);
|
||||
background: var(--sh-operator-bg);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #00a984;
|
||||
color: var(--sh-keyword-color);
|
||||
}
|
||||
|
||||
.token.function {
|
||||
color: #ff3860;
|
||||
color: var(--sh-function-color);
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #a74eb2;
|
||||
color: var(--sh-variable-color);
|
||||
}
|
||||
|
||||
.token.important,
|
||||
@@ -188,8 +189,8 @@ pre[class*="language-"] > code[class*="language-"] {
|
||||
right: 0;
|
||||
padding: inherit 0;
|
||||
margin-top: 1em;
|
||||
background: #f5f5f5;
|
||||
box-shadow: inset 5px 0 0 #99d8f3;
|
||||
background: var(--sh-highlight-background);
|
||||
box-shadow: inset 5px 0 0 var(--sh-highlight-accent);
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
line-height: inherit;
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
|
||||
export default {
|
||||
'pre[class*="language-"]': {
|
||||
color: "#363636",
|
||||
color: "var(--sh-base-color)",
|
||||
fontSize: "1rem",
|
||||
textShadow: "none",
|
||||
fontFamily: "Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace",
|
||||
fontFamily: "var(--sh-font-family)",
|
||||
direction: "ltr",
|
||||
textAlign: "left",
|
||||
whiteSpace: "pre",
|
||||
@@ -47,13 +47,13 @@ export default {
|
||||
padding: "1em",
|
||||
margin: ".5em 0",
|
||||
overflow: "auto",
|
||||
background: "#ffffff"
|
||||
background: "var(--sh-block-background)",
|
||||
},
|
||||
'code[class*="language-"]': {
|
||||
color: "#363636",
|
||||
color: "var(--sh-base-color)",
|
||||
fontSize: "1rem",
|
||||
textShadow: "none",
|
||||
fontFamily: "Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace",
|
||||
fontFamily: "var(--sh-font-family)",
|
||||
direction: "ltr",
|
||||
textAlign: "left",
|
||||
whiteSpace: "pre",
|
||||
@@ -66,140 +66,145 @@ export default {
|
||||
WebkitHyphens: "none",
|
||||
MozHyphens: "none",
|
||||
msHyphens: "none",
|
||||
hyphens: "none"
|
||||
hyphens: "none",
|
||||
},
|
||||
'pre[class*="language-"]::selection': {
|
||||
textShadow: "none",
|
||||
background: "#7fe3cd"
|
||||
background: "var(--sh-selected-color)",
|
||||
},
|
||||
'code[class*="language-"]::selection': {
|
||||
textShadow: "none",
|
||||
background: "#7fe3cd"
|
||||
background: "var(--sh-selected-color)",
|
||||
},
|
||||
'pre[class*="language-"]::-moz-selection': {
|
||||
textShadow: "none",
|
||||
background: "#7fe3cd"
|
||||
background: "var(--sh-selected-color)",
|
||||
},
|
||||
'code[class*="language-"]::-moz-selection': {
|
||||
textShadow: "none",
|
||||
background: "#7fe3cd"
|
||||
background: "var(--sh-selected-color)",
|
||||
},
|
||||
':not(pre) > code[class*="language-"]': {
|
||||
padding: ".1em .3em",
|
||||
borderRadius: ".3em",
|
||||
color: "#ff3860",
|
||||
background: "#fbe7eb"
|
||||
color: "var(--sh-inline-code-color)",
|
||||
background: "var(--sh-inline-code-background)",
|
||||
},
|
||||
".namespace": {
|
||||
Opacity: ".7"
|
||||
Opacity: ".7",
|
||||
},
|
||||
comment: {
|
||||
color: "#9a9a9a"
|
||||
color: "var(--sh-comment-color)",
|
||||
},
|
||||
prolog: {
|
||||
color: "#9a9a9a"
|
||||
color: "var(--sh-comment-color)",
|
||||
},
|
||||
doctype: {
|
||||
color: "#9a9a9a"
|
||||
color: "var(--sh-comment-color)",
|
||||
},
|
||||
cdata: {
|
||||
color: "#9a9a9a"
|
||||
color: "var(--sh-comment-color)",
|
||||
},
|
||||
punctuation: {
|
||||
color: "#9a9a9a"
|
||||
color: "var(--sh-punctuation-color)",
|
||||
},
|
||||
property: {
|
||||
color: "#2c99c7"
|
||||
color: "var(--sh-property-color)",
|
||||
},
|
||||
tag: {
|
||||
color: "#2c99c7"
|
||||
color: "var(--sh-property-color)",
|
||||
},
|
||||
boolean: {
|
||||
color: "#2c99c7"
|
||||
color: "var(--sh-property-color)",
|
||||
},
|
||||
number: {
|
||||
color: "#2c99c7"
|
||||
color: "var(--sh-property-color)",
|
||||
},
|
||||
constant: {
|
||||
color: "#2c99c7"
|
||||
color: "var(--sh-property-color)",
|
||||
},
|
||||
symbol: {
|
||||
color: "#2c99c7"
|
||||
color: "var(--sh-property-color)",
|
||||
},
|
||||
deleted: {
|
||||
color: "#2c99c7"
|
||||
color: "var(--sh-property-color)",
|
||||
},
|
||||
selector: {
|
||||
color: "#005f9a"
|
||||
color: "var(--sh-selector-color)",
|
||||
},
|
||||
"attr-name": {
|
||||
color: "#005f9a"
|
||||
color: "var(--sh-selector-color)",
|
||||
},
|
||||
string: {
|
||||
color: "#005f9a"
|
||||
color: "var(--sh-selector-color)",
|
||||
},
|
||||
char: {
|
||||
color: "#005f9a"
|
||||
color: "var(--sh-selector-color)",
|
||||
},
|
||||
builtin: {
|
||||
color: "#005f9a"
|
||||
color: "var(--sh-selector-color)",
|
||||
},
|
||||
inserted: {
|
||||
color: "#005f9a"
|
||||
color: "var(--sh-selector-color)",
|
||||
},
|
||||
operator: {
|
||||
color: "#686868"
|
||||
color: "var(--sh-operator-color)",
|
||||
background: "var(--sh-operator-bg)",
|
||||
},
|
||||
entity: {
|
||||
color: "#686868",
|
||||
cursor: "help"
|
||||
color: "var(--sh-operator-color)",
|
||||
background: "var(--sh-operator-bg)",
|
||||
cursor: "help",
|
||||
},
|
||||
url: {
|
||||
color: "#686868"
|
||||
color: "var(--sh-operator-color)",
|
||||
background: "var(--sh-operator-bg)",
|
||||
},
|
||||
".language-css .token.string": {
|
||||
color: "#686868"
|
||||
color: "var(--sh-operator-color)",
|
||||
background: "var(--sh-operator-bg)",
|
||||
},
|
||||
".style .token.string": {
|
||||
color: "#686868"
|
||||
color: "var(--sh-operator-color)",
|
||||
background: "var(--sh-operator-bg)",
|
||||
},
|
||||
atrule: {
|
||||
color: "#00a984"
|
||||
color: "var(--sh-keyword-color)",
|
||||
},
|
||||
"attr-value": {
|
||||
color: "#00a984"
|
||||
color: "var(--sh-keyword-color)",
|
||||
},
|
||||
keyword: {
|
||||
color: "#00a984"
|
||||
color: "var(--sh-keyword-color)",
|
||||
},
|
||||
function: {
|
||||
color: "#ff3860"
|
||||
color: "var(--sh-function-color)",
|
||||
},
|
||||
regex: {
|
||||
color: "#a74eb2"
|
||||
color: "var(--sh-variable-color)",
|
||||
},
|
||||
important: {
|
||||
color: "#a74eb2",
|
||||
fontWeight: "bold"
|
||||
color: "var(--sh-variable-color)",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
variable: {
|
||||
color: "#a74eb2"
|
||||
color: "var(--sh-variable-color)",
|
||||
},
|
||||
bold: {
|
||||
fontWeight: "bold"
|
||||
fontWeight: "bold",
|
||||
},
|
||||
title: {
|
||||
fontWeight: "bold"
|
||||
fontWeight: "bold",
|
||||
},
|
||||
italic: {
|
||||
fontStyle: "italic"
|
||||
fontStyle: "italic",
|
||||
},
|
||||
"pre[data-line]": {
|
||||
position: "relative"
|
||||
position: "relative",
|
||||
},
|
||||
'pre[class*="language-"] > code[class*="language-"]': {
|
||||
position: "relative",
|
||||
zIndex: "1"
|
||||
zIndex: "1",
|
||||
},
|
||||
".line-highlight": {
|
||||
position: "absolute",
|
||||
@@ -207,11 +212,11 @@ export default {
|
||||
right: "0",
|
||||
padding: "inherit 0",
|
||||
marginTop: "1em",
|
||||
background: "#f5f5f5",
|
||||
boxShadow: "inset 5px 0 0 #99d8f3",
|
||||
background: "var(--sh-highlight-background)",
|
||||
boxShadow: "inset 5px 0 0 var(--sh-highlight-accent)",
|
||||
zIndex: "0",
|
||||
pointerEvents: "none",
|
||||
lineHeight: "inherit",
|
||||
whiteSpace: "pre"
|
||||
}
|
||||
whiteSpace: "pre",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ const StyledTable = styled(Table)`
|
||||
}
|
||||
`;
|
||||
|
||||
storiesOf("Table|Table", module)
|
||||
storiesOf("Table", module)
|
||||
.add("Default", () => (
|
||||
<Table
|
||||
data={[
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"babel-loader": "^8.0.6",
|
||||
"css-loader": "^3.2.0",
|
||||
"file-loader": "^4.2.0",
|
||||
"mini-css-extract-plugin": "^0.12.0",
|
||||
"mini-css-extract-plugin": "^1.6.2",
|
||||
"mustache": "^3.1.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
"react-refresh": "^0.10.0",
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
|
||||
const WorkerPlugin = require("worker-plugin");
|
||||
@@ -46,6 +47,13 @@ if (isDevelopment) {
|
||||
webpackPlugins.push(new ReactRefreshWebpackPlugin());
|
||||
}
|
||||
|
||||
const themedir = path.join(root, "ui-styles", "src");
|
||||
const themes = fs
|
||||
.readdirSync(themedir)
|
||||
.map((filename) => path.parse(filename))
|
||||
.filter((p) => p.ext === ".scss")
|
||||
.reduce((entries, current) => ({ ...entries, [current.name]: path.join(themedir, current.base) }), {});
|
||||
|
||||
console.log(`build ${mode} bundles`);
|
||||
|
||||
module.exports = [
|
||||
@@ -163,7 +171,7 @@ module.exports = [
|
||||
{
|
||||
mode,
|
||||
context: root,
|
||||
entry: "./ui-styles/src/scm.scss",
|
||||
entry: themes,
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
@@ -184,7 +192,7 @@ module.exports = [
|
||||
},
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "ui-styles.css",
|
||||
filename: "ui-theme-[name].css",
|
||||
ignoreOrder: false
|
||||
})
|
||||
],
|
||||
@@ -193,7 +201,7 @@ module.exports = [
|
||||
},
|
||||
output: {
|
||||
path: path.join(root, "build", "webapp", "assets"),
|
||||
filename: "ui-styles.bundle.js"
|
||||
filename: "ui-theme-[name].bundle.js"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
"@scm-manager/eslint-config": "^2.12.0",
|
||||
"@scm-manager/prettier-config": "^2.10.1",
|
||||
"css-loader": "^3.2.0",
|
||||
"html-webpack-plugin": "4",
|
||||
"prettier": "^2.1.2",
|
||||
"sass": "^1.26.3",
|
||||
"raw-loader": "^4.0.2",
|
||||
"sass": "^1.43.2",
|
||||
"sass-loader": "^8.0.0",
|
||||
"style-loader": "^1.0.0",
|
||||
"webpack": "^4.41.5",
|
||||
|
||||
84
scm-ui/ui-styles/public/_index.html
Normal file
84
scm-ui/ui-styles/public/_index.html
Normal file
@@ -0,0 +1,84 @@
|
||||
<!--
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>SCM-Manager Styleguide</title>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
|
||||
<meta content="#000000" name="theme-color">
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
|
||||
font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: #00d1df;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 20px 34px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
margin: 4px 2px;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main>
|
||||
<h1>SCM-Manager Styleguide</h1>
|
||||
<h2>Choose your Theme</h2>
|
||||
<div class="themes">
|
||||
<% _.each(htmlWebpackPlugin.options.themes, function(theme){ %>
|
||||
<a href="<%= theme %>.html">
|
||||
<%= theme %>
|
||||
</a>
|
||||
<% }); %>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
2498
scm-ui/ui-styles/public/_styleguide.html
Normal file
2498
scm-ui/ui-styles/public/_styleguide.html
Normal file
File diff suppressed because it is too large
Load Diff
45
scm-ui/ui-styles/public/_theme.html
Normal file
45
scm-ui/ui-styles/public/_theme.html
Normal file
@@ -0,0 +1,45 @@
|
||||
<!--
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>SCM-Manager Styleguide</title>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
|
||||
<meta content="#000000" name="theme-color">
|
||||
<link href="ui-webapp/favicon.ico" rel="shortcut icon">
|
||||
<script data-type="theme" src="/theme-<%= htmlWebpackPlugin.options.theme %>.bundle.js" type="application/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5">
|
||||
<h1 class="title is-1">Styleguide SCM-Manager 2</h1>
|
||||
<h2 class="subtitle">Theme <%= htmlWebpackPlugin.options.theme %></h2>
|
||||
</div>
|
||||
<%= require('raw-loader!./_styleguide.html').default %>
|
||||
<script data-type="theme" src="js/styleguide.js" type="application/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
48
scm-ui/ui-styles/public/js/styleguide.js
Normal file
48
scm-ui/ui-styles/public/js/styleguide.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
const rgb2hex = (c) => "#" + c.match(/\d+/g).map((x) => (+x).toString(16).padStart(2, 0)).join``;
|
||||
|
||||
function onClickColorButton(e) {
|
||||
const button = e.target;
|
||||
|
||||
const cell = button.parentElement;
|
||||
|
||||
const div = cell.querySelector("div.color-text");
|
||||
if (div) {
|
||||
div.remove();
|
||||
} else {
|
||||
let color = window.getComputedStyle(button).backgroundColor;
|
||||
color = rgb2hex(color);
|
||||
|
||||
const colorText = document.createElement("div");
|
||||
colorText.className = "color-text";
|
||||
colorText.innerText = color;
|
||||
|
||||
cell.appendChild(colorText);
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll("table.colors span.button").forEach((button) => {
|
||||
button.addEventListener("click", onClickColorButton);
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
@@ -21,26 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
@import "bulma/sass/utilities/initial-variables";
|
||||
@import "bulma/sass/utilities/functions";
|
||||
//$link: #007EB0;
|
||||
$info: #33b2e8;
|
||||
$turquoise: #00d1df;
|
||||
$blue: #33b2e8;
|
||||
$cyan: $blue;
|
||||
$green: #00c79b;
|
||||
$warning: #ffdd57;
|
||||
$blue-light: #98d8f3;
|
||||
$danger: #ff3860;
|
||||
$high-contrast-danger: #e63453;
|
||||
$family-monospace: "Courier New", Monaco, Menlo, "Ubuntu Mono", "source-code-pro", monospace;
|
||||
$high-contrast-background-color: #050514;
|
||||
$high-contrast-light-gray: #f2f2f2;
|
||||
|
||||
.table.high-contrast, .table.high-contrast thead td, .table.high-contrast thead th {
|
||||
background-color: $high-contrast-background-color;
|
||||
color: $high-contrast-light-gray;
|
||||
}
|
||||
// TODO split into multiple files
|
||||
|
||||
.is-ellipsis-overflow {
|
||||
overflow: hidden;
|
||||
@@ -89,6 +70,7 @@ hr.header-with-actions {
|
||||
width: 100%;
|
||||
}
|
||||
.input-button {
|
||||
// TODO color def
|
||||
border: 2px solid #e9f7fd;
|
||||
padding: 1em 1em;
|
||||
margin-top: 0 !important;
|
||||
@@ -107,84 +89,6 @@ footer.footer {
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Import the rest of Bulma
|
||||
@import "bulma/bulma";
|
||||
@import "bulma-tooltip/dist/css/bulma-tooltip.min";
|
||||
@import "bulma-popover/css/bulma-popover";
|
||||
|
||||
$dark-75: scale-color($dark, $lightness: 25%);
|
||||
$dark-50: scale-color($dark, $lightness: 50%);
|
||||
$dark-25: scale-color($dark, $lightness: 75%);
|
||||
$info-75: scale-color($info, $lightness: 25%);
|
||||
$info-50: scale-color($info, $lightness: 50%);
|
||||
$info-25: scale-color($info, $lightness: 75%);
|
||||
$link-75: scale-color($link, $lightness: 25%);
|
||||
$link-50: scale-color($link, $lightness: 50%);
|
||||
$link-25: scale-color($link, $lightness: 75%);
|
||||
$primary-75: scale-color($primary, $lightness: 25%);
|
||||
$primary-50: scale-color($primary, $lightness: 50%);
|
||||
$primary-25: scale-color($primary, $lightness: 75%);
|
||||
$success-75: scale-color($success, $lightness: 25%);
|
||||
$success-50: scale-color($success, $lightness: 50%);
|
||||
$success-25: scale-color($success, $lightness: 75%);
|
||||
$warning-75: scale-color($warning, $lightness: 25%);
|
||||
$warning-50: scale-color($warning, $lightness: 50%);
|
||||
$warning-25: scale-color($warning, $lightness: 75%);
|
||||
$danger-75: scale-color($danger, $lightness: 25%);
|
||||
$danger-50: scale-color($danger, $lightness: 50%);
|
||||
$danger-25: scale-color($danger, $lightness: 75%);
|
||||
|
||||
$high-contrast-danger-75: scale-color($high-contrast-danger, $lightness: 25%);
|
||||
$high-contrast-danger-50: scale-color($high-contrast-danger, $lightness: 50%);
|
||||
$high-contrast-danger-25: scale-color($high-contrast-danger, $lightness: 75%);
|
||||
|
||||
//high-contrast light gray
|
||||
$light-75: darken($high-contrast-light-gray, 15%);
|
||||
$light-50: darken($high-contrast-light-gray, 30%);
|
||||
$light-25: darken($high-contrast-light-gray, 45%);
|
||||
/*
|
||||
// not supported by ie
|
||||
// css vars for external reuse
|
||||
:root {
|
||||
// asc sorted initial variables
|
||||
--black: #{$black};
|
||||
--white: #{$white};
|
||||
|
||||
// asc sorted derived-variables
|
||||
--primary: #{$primary};
|
||||
--primary-75: #{$primary-75};
|
||||
--primary-50: #{$primary-50};
|
||||
--primary-25: #{$primary-25};
|
||||
--info: #{$info};
|
||||
--info-75: #{$info-75};
|
||||
--info-50: #{$info-50};
|
||||
--info-25: #{$info-25};
|
||||
--success: #{$success};
|
||||
--success-75: #{$success-75};
|
||||
--success-50: #{$success-50};
|
||||
--success-25: #{$success-25};
|
||||
--warning: #{$warning};
|
||||
--warning-75: #{$warning-75};
|
||||
--warning-50: #{$warning-50};
|
||||
--warning-25: #{$warning-25};
|
||||
--danger: #{$danger};
|
||||
--danger-75: #{$danger-75};
|
||||
--danger-50: #{$danger-50};
|
||||
--danger-25: #{$danger-25};
|
||||
--light: #{$light};
|
||||
--dark: #{$dark};
|
||||
--dark-75: #{$dark-75};
|
||||
--dark-50: #{$dark-50};
|
||||
--dark-25: #{$dark-25};
|
||||
--background: #{$background};
|
||||
--border: #{$border};
|
||||
--text: #{$text};
|
||||
--link: #{$link};
|
||||
--link-75: #{$link-75};
|
||||
--link-50: #{$link-50};
|
||||
--link-25: #{$link-25};
|
||||
}
|
||||
*/
|
||||
|
||||
.has-hover-background-blue:hover {
|
||||
background-color: scale-color($blue, $alpha: -90%);
|
||||
@@ -192,6 +96,7 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
|
||||
// readability issues with original color
|
||||
.has-text-warning {
|
||||
// TODO color def
|
||||
color: #ffb600 !important;
|
||||
}
|
||||
.has-text-warning-invert {
|
||||
@@ -205,6 +110,8 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
background-color: $blue-light;
|
||||
}
|
||||
|
||||
// TODO
|
||||
/*
|
||||
.has-text-high-contrast-warning {
|
||||
color: $warning;
|
||||
}
|
||||
@@ -213,7 +120,7 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
}
|
||||
.has-text-high-contrast-light-gray {
|
||||
color: $high-contrast-light-gray;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
// border and background colors
|
||||
@@ -281,7 +188,8 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
background-color: $danger-25;
|
||||
}
|
||||
|
||||
.has-background-danger-high-contrast {
|
||||
// TODO
|
||||
/*.has-background-danger-high-contrast {
|
||||
background-color: $high-contrast-danger;
|
||||
}
|
||||
.has-background-danger-high-contrast-75 {
|
||||
@@ -305,7 +213,7 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
}
|
||||
.has-background-high-contrast-light-gray-25 {
|
||||
background-color: $light-25;
|
||||
}
|
||||
}*/
|
||||
|
||||
// tags
|
||||
.tag:not(body) {
|
||||
@@ -373,10 +281,6 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
height: 2.5rem;
|
||||
font-weight: $weight-semibold;
|
||||
|
||||
&[disabled] {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.is-primary,
|
||||
&.is-info,
|
||||
&.is-link,
|
||||
@@ -388,10 +292,6 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-warning {
|
||||
color: #88550D;
|
||||
}
|
||||
|
||||
&.is-primary:hover,
|
||||
&.is-primary.is-hovered {
|
||||
background-color: scale-color($primary, $lightness: -10%);
|
||||
@@ -402,10 +302,6 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
background-color: scale-color($primary, $lightness: -20%);
|
||||
}
|
||||
|
||||
&.is-primary[disabled] {
|
||||
background-color: scale-color($primary, $lightness: 75%);
|
||||
}
|
||||
|
||||
&.is-info:hover,
|
||||
&.is-info.is-hovered {
|
||||
background-color: scale-color($info, $lightness: -10%);
|
||||
@@ -416,10 +312,6 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
background-color: scale-color($info, $lightness: -20%);
|
||||
}
|
||||
|
||||
&.is-info[disabled] {
|
||||
background-color: scale-color($info, $lightness: 75%);
|
||||
}
|
||||
|
||||
&.is-link:hover,
|
||||
&.is-link.is-hovered {
|
||||
background-color: scale-color($link, $lightness: -10%);
|
||||
@@ -430,10 +322,6 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
background-color: scale-color($link, $lightness: -20%);
|
||||
}
|
||||
|
||||
&.is-link[disabled] {
|
||||
background-color: scale-color($link, $lightness: 75%);
|
||||
}
|
||||
|
||||
&.is-success:hover,
|
||||
&.is-success.is-hovered {
|
||||
background-color: scale-color($success, $lightness: -10%);
|
||||
@@ -444,10 +332,6 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
background-color: scale-color($success, $lightness: -20%);
|
||||
}
|
||||
|
||||
&.is-success[disabled] {
|
||||
background-color: scale-color($success, $lightness: 75%);
|
||||
}
|
||||
|
||||
&.is-warning:hover,
|
||||
&.is-warning.is-hovered {
|
||||
background-color: scale-color($warning, $lightness: -10%);
|
||||
@@ -458,11 +342,6 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
background-color: scale-color($warning, $lightness: -20%);
|
||||
}
|
||||
|
||||
&.is-warning[disabled] {
|
||||
background-color: scale-color($warning, $lightness: 75%);
|
||||
color: #e1d4c2;
|
||||
}
|
||||
|
||||
&.is-danger:hover,
|
||||
&.is-danger.is-hovered {
|
||||
background-color: scale-color($danger, $lightness: -10%);
|
||||
@@ -473,10 +352,6 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
||||
background-color: scale-color($danger, $lightness: -20%);
|
||||
}
|
||||
|
||||
&.is-danger[disabled] {
|
||||
background-color: scale-color($danger, $lightness: 75%);
|
||||
}
|
||||
|
||||
&.is-reduced-mobile,
|
||||
&.reduced-mobile {
|
||||
@media screen and (max-width: 1087px) {
|
||||
@@ -520,9 +395,6 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
|
||||
// NEW STYLES
|
||||
|
||||
//typography
|
||||
.subtitle {
|
||||
color: #666;
|
||||
}
|
||||
.has-border-white {
|
||||
border-color: $white !important;
|
||||
}
|
||||
@@ -889,7 +761,7 @@ form .field:not(.is-grouped) {
|
||||
}
|
||||
|
||||
a:before {
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-family: "Font Awesome 5 Free"; /* NOSONAR */
|
||||
font-weight: 900;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
display: inline-block;
|
||||
@@ -952,3 +824,7 @@ form .field:not(.is-grouped) {
|
||||
@include loader;
|
||||
}
|
||||
}
|
||||
|
||||
.sg-sub-section + .sg-sub-section {
|
||||
margin-top: 2.5rem;
|
||||
}
|
||||
334
scm-ui/ui-styles/src/highcontrast.scss
Normal file
334
scm-ui/ui-styles/src/highcontrast.scss
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
@import "utils/_pre.scss";
|
||||
|
||||
// $text: $white;
|
||||
$scheme-main: #050514;
|
||||
$background: $grey-dark;
|
||||
$text: $white-ter;
|
||||
$text-strong: $white-bis;
|
||||
|
||||
$red: #e63453;
|
||||
// TODO check if we could replace red in commons,
|
||||
// without breaking the light mode
|
||||
$danger: $red;
|
||||
|
||||
$code: lighten($red, 25%);
|
||||
$primary-invert: #050514;
|
||||
$info-invert: #050514;
|
||||
$link-invert: #050514;
|
||||
$link-hover: $white-bis;
|
||||
$success-invert: #050514;
|
||||
$danger-invert: #050514;
|
||||
|
||||
$light-gray: #f2f2f2;
|
||||
|
||||
$footer-background-color: $grey-dark;
|
||||
$footer-color: $white-ter;
|
||||
|
||||
$box-background-color: scale-color($scheme-main, $lightness: 15%);
|
||||
$box-background-color: $grey-darker;
|
||||
|
||||
$modal-card-head-background-color: $grey-dark;
|
||||
$modal-card-body-background-color: $scheme-main;
|
||||
|
||||
$input-placeholder-color: $white;
|
||||
|
||||
$popover-background-color: $grey-dark;
|
||||
|
||||
$table-row-hover-background-color: $grey-darker;
|
||||
|
||||
$tooltip-background-color: $white-bis;
|
||||
$tooltip-background-opacity: 0.9 !default;
|
||||
$tooltip-color: $scheme-main;
|
||||
|
||||
// WTF
|
||||
$high-contrast-background-color: #050514;
|
||||
$high-contrast-light-gray: #f2f2f2;
|
||||
|
||||
@import "utils/_post.scss";
|
||||
|
||||
|
||||
:root {
|
||||
--sh-base-color: #fff;
|
||||
--sh-font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
--sh-block-background: #000;
|
||||
--sh-inline-code-color: #ff3860;
|
||||
--sh-inline-code-background: #fbe7eb;
|
||||
--sh-comment-color: #9a9a9a;
|
||||
--sh-punctuation-color: #999999;
|
||||
--sh-property-color: #2c99c7;
|
||||
--sh-selector-color: #009dff;
|
||||
--sh-operator-color: #999999;
|
||||
--sh-operator-bg: inherit;
|
||||
--sh-variable-color: #C386CA;
|
||||
--sh-function-color: #FF6181;
|
||||
--sh-keyword-color: #00a984;
|
||||
--sh-selected-color: #7fe3cd;
|
||||
--sh-highlight-background: #f5f5f5;
|
||||
--sh-highlight-accent: #99d8f3;
|
||||
|
||||
--diff-background-color: $scheme-main;
|
||||
--diff-text-color: $white-bis;
|
||||
--diff-font-family: Consolas, Courier, monospace;
|
||||
--diff-selection-background-color: #b3d7ff;
|
||||
--diff-gutter-insert-background-color: #05C71D;
|
||||
--diff-gutter-delete-background-color: #EB7A85;
|
||||
--diff-gutter-selected-background-color: #fffce0;
|
||||
--diff-code-insert-background-color: #05240B;
|
||||
--diff-code-delete-background-color: #230608;
|
||||
--diff-code-insert-edit-background-color: #c0dc91;
|
||||
--diff-code-delete-edit-background-color: #000;
|
||||
--diff-code-selected-background-color: #fffce0;
|
||||
--diff-omit-gutter-line-color: #cb2a1d;
|
||||
}
|
||||
|
||||
|
||||
.button {
|
||||
|
||||
&.is-danger:hover,
|
||||
&.is-danger.is-hovered {
|
||||
background-color: scale-color($danger, $lightness: -2.5%);
|
||||
}
|
||||
|
||||
&.is-danger:active,
|
||||
&.is-danger.is-active {
|
||||
background-color: scale-color($danger, $lightness: -4%);
|
||||
}
|
||||
|
||||
&.is-primary,
|
||||
&.is-info,
|
||||
&.is-link,
|
||||
&.is-success,
|
||||
&.is-warning,
|
||||
&.is-danger {
|
||||
&.is-outlined {
|
||||
background-color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
color: $scheme-main;
|
||||
}
|
||||
|
||||
.menu-list {
|
||||
a {
|
||||
color: $white-ter;
|
||||
|
||||
&.is-active {
|
||||
background-color: $high-contrast-background-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
//footer is overwritten in _main.scss
|
||||
footer.footer {
|
||||
background-color: $grey-dark;
|
||||
a{
|
||||
color: scale-color($link, $lightness:25%);
|
||||
}
|
||||
}
|
||||
//card
|
||||
|
||||
.modal-card {
|
||||
border: 1px solid $white-ter;
|
||||
.modal-close::before, .delete::before, .modal-close::after, .delete::after {
|
||||
background-color: $white-bis;
|
||||
}
|
||||
}
|
||||
|
||||
//card tables
|
||||
.card-table {
|
||||
tr {
|
||||
a {
|
||||
color: $white-bis;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
td {
|
||||
background-color: $grey-darker;
|
||||
|
||||
&.is-darker {
|
||||
background-color: $grey-darker;
|
||||
}
|
||||
}
|
||||
a {
|
||||
color: $link;
|
||||
}
|
||||
}
|
||||
}
|
||||
td {
|
||||
background-color: $grey-dark;
|
||||
border-bottom: 1px solid $grey;
|
||||
&.is-darker {
|
||||
background-color: $grey-dark;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-hoverable tbody tr:not(.is-selected):hover {
|
||||
background-color: $grey-darker;
|
||||
}
|
||||
}
|
||||
|
||||
// panels
|
||||
.panel {
|
||||
border: 1px solid $white-bis;
|
||||
border-radius: 0.25rem;
|
||||
|
||||
.panel-heading {
|
||||
border: none;
|
||||
border-bottom: 1px solid $border;
|
||||
border-radius: 0.25rem 0.25rem 0 0;
|
||||
background-color: $grey-darker;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
background-color: $grey-darker;
|
||||
color: $white-bis;
|
||||
font-size: 1.25em;
|
||||
font-weight: 300;
|
||||
line-height: 1.25;
|
||||
padding: 0.5em 0.75em;
|
||||
border: none;
|
||||
border-top: 1px solid $border;
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
//diffs
|
||||
.diff-code-conflict {
|
||||
background-color: #332900;
|
||||
}
|
||||
|
||||
.diff-gutter-conflict {
|
||||
background-color: #FFD11A;
|
||||
}
|
||||
|
||||
.diff-gutter-delete,.diff-gutter-insert, .diff-gutter-conflict {
|
||||
color: $scheme-main;
|
||||
}
|
||||
|
||||
/* transport meaning with more than color */
|
||||
td:nth-child(2).diff-gutter-delete:before {
|
||||
content: "-";
|
||||
}
|
||||
|
||||
td:first-child.diff-gutter-insert:before {
|
||||
content: "+";
|
||||
}
|
||||
|
||||
td:first-child.diff-gutter-conflict:before {
|
||||
content: "!";
|
||||
}
|
||||
|
||||
.diff-split td:nth-child(3).diff-gutter-insert:before {
|
||||
content: "+";
|
||||
}
|
||||
|
||||
.diff-split td:first-child.diff-gutter-delete:before {
|
||||
content: "-";
|
||||
}
|
||||
|
||||
.diff-split td:nth-child(3).diff-gutter-conflict:before {
|
||||
content: "!";
|
||||
}
|
||||
|
||||
.diff-decoration-content div {
|
||||
color: $scheme-main;
|
||||
}
|
||||
|
||||
//inline member tags
|
||||
.tag:not(body) {
|
||||
border: 1px solid transparent;
|
||||
background-color: $white;
|
||||
.is-delete::before, .is-delete::after {
|
||||
background-color: $scheme-main;
|
||||
}
|
||||
}
|
||||
|
||||
.tag:not(body).is-delete::before, .tag:not(body).is-delete::after {
|
||||
background-color: $scheme-main;
|
||||
}
|
||||
.tag:not(body).is-delete:hover::before, .tag:not(body).is-delete:hover::after {
|
||||
background-color: $white-bis;
|
||||
}
|
||||
|
||||
//dark tags have light borders to separate from background
|
||||
.tag:not(body).is-dark, .tag:not(body).is-black {
|
||||
border: 1px solid $white-bis;
|
||||
}
|
||||
|
||||
//blue text in light tags
|
||||
.tag.is-light .has-text-link {
|
||||
color: scale-color($link, $lightness: -50%) !important;
|
||||
}
|
||||
//outline-tags
|
||||
.tag:not(body).is-outlined {
|
||||
background-color: $scheme-main;
|
||||
}
|
||||
|
||||
//cards receive white border
|
||||
.box-link-shadow {
|
||||
box-shadow: 0 0 0 1px $white-bis;
|
||||
}
|
||||
|
||||
//some modals have lighter backgrounds in head
|
||||
//TODO: fix with meta-class (contains light color in light-mode, dark color in dark mode
|
||||
.has-background-light {
|
||||
background-color: $grey-dark !important;
|
||||
}
|
||||
|
||||
//they also often have black text, this is a stop-gap
|
||||
//TODO: fix with meta-class (contains dark color in light-mode, light color in dark mode
|
||||
.modal-card-title.has-text-black {
|
||||
color: $white-bis !important;
|
||||
}
|
||||
|
||||
//fix triangle for pop-overs
|
||||
.popover {
|
||||
color: #00a984;
|
||||
}
|
||||
.popover .popover-content::before
|
||||
{
|
||||
border-bottom-color: $grey-dark !important;
|
||||
border-left-color: $grey-dark !important;
|
||||
}
|
||||
|
||||
//make horizontal lines pop more
|
||||
hr {
|
||||
background-color: $white-bis;
|
||||
}
|
||||
|
||||
//Login and logout overwrite white-ter background
|
||||
.hero-body .has-background-white-ter {
|
||||
background-color: $grey-dark !important;
|
||||
}
|
||||
|
||||
//Display darker version of background image
|
||||
.has-scm-background {
|
||||
background-image: url(images/scmManagerHeroDark.jpg) !important;
|
||||
background-size: cover;
|
||||
background-position: top center;
|
||||
}
|
||||
BIN
scm-ui/ui-styles/src/images/scmManagerHeroDark.jpg
Normal file
BIN
scm-ui/ui-styles/src/images/scmManagerHeroDark.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
52
scm-ui/ui-styles/src/light.scss
Normal file
52
scm-ui/ui-styles/src/light.scss
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
@import "utils/_pre.scss";
|
||||
// colors defined in variables/commons.scss
|
||||
$subtitle-color: #666;
|
||||
$warning-invert: #88550D;
|
||||
$button-disabled-opacity: .25;
|
||||
|
||||
@import "utils/_post.scss";
|
||||
|
||||
:root {
|
||||
--sh-base-color: #363636;
|
||||
--sh-font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
--sh-block-background: #ffffff;
|
||||
--sh-inline-code-color: #ff3860;
|
||||
--sh-inline-code-background: #fbe7eb;
|
||||
--sh-comment-color: #9a9a9a;
|
||||
--sh-punctuation-color: #9a9a9a;
|
||||
--sh-property-color: #2c99c7;
|
||||
--sh-selector-color: #005f9a;
|
||||
--sh-operator-color: #686868;
|
||||
--sh-operator-bg: inherit;
|
||||
--sh-variable-color: #a74eb2;
|
||||
--sh-function-color: #ff3860;
|
||||
--sh-keyword-color: #00a984;
|
||||
--sh-selected-color: #7fe3cd;
|
||||
--sh-highlight-background: #f5f5f5;
|
||||
--sh-highlight-accent: #99d8f3;
|
||||
}
|
||||
|
||||
28
scm-ui/ui-styles/src/utils/_post.scss
Normal file
28
scm-ui/ui-styles/src/utils/_post.scss
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
@import "bulma/bulma";
|
||||
@import "../variables/_derived.scss";
|
||||
@import "bulma-tooltip/dist/css/bulma-tooltip.min";
|
||||
@import "bulma-popover/css/bulma-popover";
|
||||
@import "../components/_main.scss";
|
||||
@@ -21,4 +21,6 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import "storybook-addon-i18next/register";
|
||||
@import "bulma/sass/utilities/initial-variables";
|
||||
@import "bulma/sass/utilities/functions";
|
||||
@import "../variables/_commons.scss";
|
||||
34
scm-ui/ui-styles/src/variables/_commons.scss
Normal file
34
scm-ui/ui-styles/src/variables/_commons.scss
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
//$link: #007EB0;
|
||||
$info: #33b2e8;
|
||||
$turquoise: #00d1df;
|
||||
$blue: #33b2e8;
|
||||
$cyan: $blue;
|
||||
$green: #00c79b;
|
||||
$warning: #ffdd57;
|
||||
$blue-light: #98d8f3;
|
||||
$danger: #ff3860;
|
||||
|
||||
$family-monospace: "Courier New", Monaco, Menlo, "Ubuntu Mono", "source-code-pro", monospace;
|
||||
55
scm-ui/ui-styles/src/variables/_derived.scss
Normal file
55
scm-ui/ui-styles/src/variables/_derived.scss
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
$dark-75: scale-color($dark, $lightness: 25%);
|
||||
$dark-50: scale-color($dark, $lightness: 50%);
|
||||
$dark-25: scale-color($dark, $lightness: 75%);
|
||||
$info-75: scale-color($info, $lightness: 25%);
|
||||
$info-50: scale-color($info, $lightness: 50%);
|
||||
$info-25: scale-color($info, $lightness: 75%);
|
||||
$link-75: scale-color($link, $lightness: 25%);
|
||||
$link-50: scale-color($link, $lightness: 50%);
|
||||
$link-25: scale-color($link, $lightness: 75%);
|
||||
$primary-75: scale-color($primary, $lightness: 25%);
|
||||
$primary-50: scale-color($primary, $lightness: 50%);
|
||||
$primary-25: scale-color($primary, $lightness: 75%);
|
||||
$success-75: scale-color($success, $lightness: 25%);
|
||||
$success-50: scale-color($success, $lightness: 50%);
|
||||
$success-25: scale-color($success, $lightness: 75%);
|
||||
$warning-75: scale-color($warning, $lightness: 25%);
|
||||
$warning-50: scale-color($warning, $lightness: 50%);
|
||||
$warning-25: scale-color($warning, $lightness: 75%);
|
||||
$danger-75: scale-color($danger, $lightness: 25%);
|
||||
$danger-50: scale-color($danger, $lightness: 50%);
|
||||
$danger-25: scale-color($danger, $lightness: 75%);
|
||||
|
||||
// TODO
|
||||
// $high-contrast-danger-75: scale-color($high-contrast-danger, $lightness: 25%);
|
||||
// $high-contrast-danger-50: scale-color($high-contrast-danger, $lightness: 50%);
|
||||
// $high-contrast-danger-25: scale-color($high-contrast-danger, $lightness: 75%);
|
||||
|
||||
// TODO
|
||||
// high-contrast light gray
|
||||
// $light-75: darken($high-contrast-light-gray, 15%);
|
||||
// $light-50: darken($high-contrast-light-gray, 30%);
|
||||
// $light-25: darken($high-contrast-light-gray, 45%);
|
||||
@@ -22,9 +22,36 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
|
||||
const themes = fs
|
||||
.readdirSync("src")
|
||||
.map((filename) => path.parse(filename))
|
||||
.filter((p) => p.ext === ".scss")
|
||||
.reduce((entries, current) => ({ ...entries, [current.name]: `./src/${current.base}` }), {});
|
||||
|
||||
const plugins = Object.keys(themes).map(
|
||||
(theme) =>
|
||||
new HtmlWebpackPlugin({
|
||||
filename: `${theme}.html`,
|
||||
template: "./public/_theme.html",
|
||||
inject: false,
|
||||
theme,
|
||||
})
|
||||
);
|
||||
|
||||
plugins.push(
|
||||
new HtmlWebpackPlugin({
|
||||
filename: "index.html",
|
||||
template: "./public/_index.html",
|
||||
inject: false,
|
||||
themes: Object.keys(themes),
|
||||
})
|
||||
);
|
||||
|
||||
module.exports = {
|
||||
entry: "./src/scm.scss",
|
||||
entry: themes,
|
||||
devtool: "cheap-module-eval-source-map",
|
||||
target: "web",
|
||||
module: {
|
||||
@@ -37,23 +64,25 @@ module.exports = {
|
||||
// Translates CSS into CommonJS
|
||||
"css-loader",
|
||||
// Compiles Sass to CSS
|
||||
"sass-loader"
|
||||
]
|
||||
"sass-loader",
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(png|svg|jpg|gif|woff2?|eot|ttf)$/,
|
||||
use: ["file-loader"]
|
||||
}
|
||||
]
|
||||
use: ["file-loader"],
|
||||
},
|
||||
],
|
||||
},
|
||||
output: {
|
||||
filename: "ui-styles.bundle.js"
|
||||
filename: "theme-[name].bundle.js",
|
||||
},
|
||||
plugins,
|
||||
devServer: {
|
||||
contentBase: [path.join(__dirname, "public"), path.join(__dirname, "..", "ui-webapp", "public")],
|
||||
contentBasePublicPath: ["/", "/ui-webapp"],
|
||||
compress: false,
|
||||
overlay: true,
|
||||
port: 5000
|
||||
}
|
||||
port: 5000,
|
||||
hot: true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
<base href="{{ contextPath }}">
|
||||
<title>SCM-Manager</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{{ contextPath }}/assets/ui-styles.css">
|
||||
<script>
|
||||
var modernBrowser = (
|
||||
'fetch' in window &&
|
||||
@@ -27,6 +25,16 @@
|
||||
scriptElement.src = "{{ contextPath }}/assets/polyfills.bundle.js";
|
||||
document.head.appendChild(scriptElement);
|
||||
}
|
||||
var linkElement = document.createElement("link");
|
||||
linkElement.rel = 'stylesheet';
|
||||
linkElement.type = 'text/css';
|
||||
var theme = localStorage.getItem('scm.theme');
|
||||
if (theme === 'highcontrast') {
|
||||
linkElement.href = "{{ contextPath }}/assets/ui-theme-highcontrast.css"
|
||||
} else {
|
||||
linkElement.href = "{{ contextPath }}/assets/ui-theme-light.css"
|
||||
}
|
||||
document.head.appendChild(linkElement);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -36,16 +44,6 @@
|
||||
<div id="root"></div>
|
||||
<div id="modalRoot"></div>
|
||||
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
<script>
|
||||
window.ctxPath = "{{ contextPath }}";
|
||||
window.scmStage = "{{ scmStage }}";
|
||||
|
||||
@@ -94,7 +94,23 @@
|
||||
"error-title": "Fehler",
|
||||
"error-subtitle": "Das Profil kann nicht angezeigt werden.",
|
||||
"error": "Fehler",
|
||||
"error-message": "'me' ist nicht definiert"
|
||||
"error-message": "'me' ist nicht definiert",
|
||||
"theme": {
|
||||
"nav": {
|
||||
"label": "Design",
|
||||
"title": "Wähle dein Design"
|
||||
},
|
||||
"subtitle": "Wähle dein Design",
|
||||
"submit": "Anwenden",
|
||||
"light": {
|
||||
"displayName": "Hell",
|
||||
"description": "'Hell' is das Standard-Design des SCM-Managers"
|
||||
},
|
||||
"highcontrast": {
|
||||
"displayName": "Hoher Kontrast",
|
||||
"description": "'Hoher Kontrast' ist ein dunkles Design mit einem hohen Kontrast"
|
||||
}
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"subtitle": "Passwort ändern",
|
||||
|
||||
@@ -95,7 +95,23 @@
|
||||
"error-title": "Error",
|
||||
"error-subtitle": "Cannot display profile",
|
||||
"error": "Error",
|
||||
"error-message": "'me' is undefined"
|
||||
"error-message": "'me' is undefined",
|
||||
"theme": {
|
||||
"nav": {
|
||||
"label": "Theme",
|
||||
"title": "Choose your Theme"
|
||||
},
|
||||
"subtitle": "Choose your Theme",
|
||||
"submit": "Activate",
|
||||
"light": {
|
||||
"displayName": "Light",
|
||||
"description": "The light mode is the SCM-Manager default theme"
|
||||
},
|
||||
"highcontrast": {
|
||||
"displayName": "High contrast",
|
||||
"description": "The high contrast mode is a dark theme with a high contrast between the colors"
|
||||
}
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"subtitle": "Change Password",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import React, { FC } from "react";
|
||||
import { Redirect, Route, Switch, useRouteMatch } from "react-router-dom";
|
||||
import { Redirect, Route, useRouteMatch } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
CustomQueryFlexWrappedColumns,
|
||||
@@ -38,12 +38,13 @@ import {
|
||||
} from "@scm-manager/ui-components";
|
||||
import ChangeUserPassword from "./ChangeUserPassword";
|
||||
import ProfileInfo from "./ProfileInfo";
|
||||
import { binder, ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||
import SetPublicKeys from "../users/components/publicKeys/SetPublicKeys";
|
||||
import SetPublicKeysNavLink from "../users/components/navLinks/SetPublicKeysNavLink";
|
||||
import SetApiKeys from "../users/components/apiKeys/SetApiKeys";
|
||||
import SetApiKeysNavLink from "../users/components/navLinks/SetApiKeysNavLink";
|
||||
import { useRequiredMe } from "@scm-manager/ui-api";
|
||||
import Theme from "./Theme";
|
||||
|
||||
const Profile: FC = () => {
|
||||
const match = useRouteMatch();
|
||||
@@ -55,13 +56,6 @@ const Profile: FC = () => {
|
||||
const canManagePublicKeys = !!me._links.publicKeys;
|
||||
const canManageApiKeys = !!me._links.apiKeys;
|
||||
|
||||
const shouldRenderNavigation = !!(
|
||||
me._links.password ||
|
||||
me._links.publicKeys ||
|
||||
me._links.apiKeys ||
|
||||
binder.hasExtension("profile.route")
|
||||
);
|
||||
|
||||
if (!me) {
|
||||
return (
|
||||
<ErrorPage
|
||||
@@ -85,14 +79,13 @@ const Profile: FC = () => {
|
||||
<Page title={me.displayName}>
|
||||
<CustomQueryFlexWrappedColumns>
|
||||
<PrimaryContentColumn>
|
||||
<Route path={url} exact render={() => <ProfileInfo me={me} />} />
|
||||
{shouldRenderNavigation && (
|
||||
<Switch>
|
||||
{mayChangePassword && <Redirect exact from={`${url}/settings/`} to={`${url}/settings/password`} />}
|
||||
{canManagePublicKeys && <Redirect exact from={`${url}/settings/`} to={`${url}/settings/publicKeys`} />}
|
||||
{canManageApiKeys && <Redirect exact from={`${url}/settings/`} to={`${url}/settings/apiKeys`} />}
|
||||
</Switch>
|
||||
)}
|
||||
<Route path={url} exact>
|
||||
<ProfileInfo me={me} />
|
||||
</Route>
|
||||
<Redirect exact from={`${url}/settings/`} to={`${url}/settings/theme`} />
|
||||
<Route path={`${url}/settings/theme`} exact>
|
||||
<Theme />
|
||||
</Route>
|
||||
{mayChangePassword && (
|
||||
<Route path={`${url}/settings/password`}>
|
||||
<ChangeUserPassword me={me} />
|
||||
@@ -118,12 +111,17 @@ const Profile: FC = () => {
|
||||
label={t("profile.informationNavLink")}
|
||||
title={t("profile.informationNavLink")}
|
||||
/>
|
||||
{shouldRenderNavigation && (
|
||||
<SubNavigation
|
||||
to={`${url}/settings/`}
|
||||
to={`${url}/settings/theme`}
|
||||
label={t("profile.settingsNavLink")}
|
||||
title={t("profile.settingsNavLink")}
|
||||
>
|
||||
<NavLink
|
||||
to={`${url}/settings/theme`}
|
||||
icon="fas fa-palette"
|
||||
label={t("profile.theme.nav.label")}
|
||||
title={t("profile.theme.nav.title")}
|
||||
/>
|
||||
{mayChangePassword && (
|
||||
<NavLink to={`${url}/settings/password`} label={t("profile.changePasswordNavLink")} />
|
||||
)}
|
||||
@@ -131,7 +129,6 @@ const Profile: FC = () => {
|
||||
<SetApiKeysNavLink user={me} apiKeyUrl={`${url}/settings/apiKeys`} />
|
||||
<ExtensionPoint name="profile.setting" props={extensionProps} renderAll={true} />
|
||||
</SubNavigation>
|
||||
)}
|
||||
</SecondaryNavigation>
|
||||
</SecondaryNavigationColumn>
|
||||
</CustomQueryFlexWrappedColumns>
|
||||
|
||||
101
scm-ui/ui-webapp/src/containers/Theme.tsx
Normal file
101
scm-ui/ui-webapp/src/containers/Theme.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import React, { FC, useState } from "react";
|
||||
import { Radio, SubmitButton, Subtitle } from "@scm-manager/ui-components";
|
||||
import { useForm } from "react-hook-form";
|
||||
import styled from "styled-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const LS_KEY = "scm.theme";
|
||||
|
||||
const useThemeState = () => {
|
||||
const [theme] = useState(localStorage.getItem(LS_KEY) || "light");
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
|
||||
const setTheme = (name: string) => {
|
||||
setLoading(true);
|
||||
localStorage.setItem(LS_KEY, name);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
return { theme, setTheme, isLoading };
|
||||
};
|
||||
|
||||
type ThemeForm = {
|
||||
theme: string;
|
||||
};
|
||||
|
||||
const themes = ["light", "highcontrast"];
|
||||
|
||||
const RadioColumn = styled.div`
|
||||
flex: none;
|
||||
width: 2rem;
|
||||
`;
|
||||
|
||||
const Theme: FC = () => {
|
||||
const { theme, setTheme, isLoading } = useThemeState();
|
||||
const {
|
||||
register,
|
||||
setValue,
|
||||
handleSubmit,
|
||||
formState: { isDirty },
|
||||
} = useForm<ThemeForm>({
|
||||
mode: "onChange",
|
||||
defaultValues: {
|
||||
theme,
|
||||
},
|
||||
});
|
||||
const [t] = useTranslation("commons");
|
||||
|
||||
const onSubmit = (values: ThemeForm) => {
|
||||
setTheme(values.theme);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Subtitle>{t("profile.theme.subtitle")}</Subtitle>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
{themes.map((theme) => (
|
||||
<div
|
||||
key={theme}
|
||||
onClick={() => setValue("theme", theme, { shouldDirty: true })}
|
||||
className="card ml-1 mb-5 control columns is-vcentered has-cursor-pointer"
|
||||
>
|
||||
<RadioColumn className="column">
|
||||
<Radio {...register("theme")} value={theme} disabled={isLoading} />
|
||||
</RadioColumn>
|
||||
<div className="column content">
|
||||
<h3>{t(`profile.theme.${theme}.displayName`)}</h3>
|
||||
<p>{t(`profile.theme.${theme}.description`)}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<SubmitButton label={t("profile.theme.submit")} loading={isLoading} disabled={!isDirty} />
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Theme;
|
||||
Reference in New Issue
Block a user