mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 01:31:17 +00:00
Merge pull request #954 from weaveworks/contrast-mode
High contrast mode switch
This commit is contained in:
@@ -51,7 +51,7 @@ export default class App extends React.Component {
|
||||
AppStore.addListener(this.onChange);
|
||||
window.addEventListener('keyup', this.onKeyPress);
|
||||
|
||||
getRouter().start({hashbang: true});
|
||||
getRouter(this.props.base).start({hashbang: true});
|
||||
if (!AppStore.isRouteSet()) {
|
||||
// dont request topologies when already done via router
|
||||
getTopologies(AppStore.getActiveTopologyOptions());
|
||||
@@ -75,6 +75,10 @@ export default class App extends React.Component {
|
||||
// width of details panel blocking a view
|
||||
const detailsWidth = showingDetails ? 450 : 0;
|
||||
const topMargin = 100;
|
||||
const contrastMode = this.props.base.indexOf('contrast') > -1;
|
||||
// link url to switch contrast with current UI state
|
||||
const otherContrastModeUrl = contrastMode ? '/' : '/contrast.html';
|
||||
const otherContrastModeTitle = contrastMode ? 'Switch to normal contrast' : 'Switch to high contrast';
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
@@ -112,9 +116,12 @@ export default class App extends React.Component {
|
||||
{this.state.version}
|
||||
<span className="footer-label">on</span>
|
||||
{this.state.hostname}
|
||||
|
||||
<a className="footer-label" href="https://gitreports.com/issue/weaveworks/scope" target="_blank">
|
||||
Report an issue
|
||||
|
||||
<a className="footer-label footer-label-icon" href={otherContrastModeUrl} title={otherContrastModeTitle}>
|
||||
<span className="fa fa-adjust" />
|
||||
</a>
|
||||
<a className="footer-label footer-label-icon" href="https://gitreports.com/issue/weaveworks/scope" target="_blank" title="Report an issue">
|
||||
<span className="fa fa-bug" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
9
client/app/scripts/contrast-main.js
Normal file
9
client/app/scripts/contrast-main.js
Normal file
@@ -0,0 +1,9 @@
|
||||
require('font-awesome-webpack');
|
||||
require('../styles/contrast.less');
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import App from './components/app.js';
|
||||
|
||||
ReactDOM.render(<App base="/contrast.html" />, document.getElementById('app'));
|
||||
@@ -6,4 +6,4 @@ import ReactDOM from 'react-dom';
|
||||
|
||||
import App from './components/app.js';
|
||||
|
||||
ReactDOM.render(<App/>, document.getElementById('app'));
|
||||
ReactDOM.render(<App base="" />, document.getElementById('app'));
|
||||
|
||||
@@ -59,7 +59,9 @@ export function getNodeColorDark(text = '', secondText = '', isPseudo = false) {
|
||||
let hsl = color.hsl();
|
||||
|
||||
// ensure darkness
|
||||
if (hsl.l > 0.7) {
|
||||
if (hsl.h > 20 && hsl.h < 120) {
|
||||
hsl = hsl.darker(2);
|
||||
} else if (hsl.l > 0.7) {
|
||||
hsl = hsl.darker(1.5);
|
||||
} else {
|
||||
hsl = hsl.darker(1);
|
||||
|
||||
@@ -16,7 +16,9 @@ export function updateRoute() {
|
||||
const state = AppStore.getAppState();
|
||||
const stateUrl = JSON.stringify(state);
|
||||
const dispatch = false;
|
||||
const urlStateString = window.location.hash.replace('#!/state/', '') || '{}';
|
||||
const urlStateString = window.location.hash
|
||||
.replace('#!/state/', '')
|
||||
.replace('#!/', '') || '{}';
|
||||
const prevState = JSON.parse(urlStateString);
|
||||
|
||||
if (shouldReplaceState(prevState, state)) {
|
||||
@@ -36,6 +38,7 @@ page('/state/:state', function(ctx) {
|
||||
route(state);
|
||||
});
|
||||
|
||||
export function getRouter() {
|
||||
export function getRouter(base) {
|
||||
page.base(base);
|
||||
return page;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ import { clearControlError, closeWebsocket, openWebsocket, receiveError,
|
||||
|
||||
import { API_INTERVAL, TOPOLOGY_INTERVAL } from '../constants/timer';
|
||||
|
||||
const wsProto = location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
const wsUrl = wsProto + '://' + location.host + location.pathname.replace(/\/$/, '');
|
||||
const log = debug('scope:web-api-utils');
|
||||
|
||||
const reconnectTimerInterval = 5000;
|
||||
@@ -47,6 +45,9 @@ export function basePath(urlPath) {
|
||||
return parts.join('/').replace(/\/$/, '');
|
||||
}
|
||||
|
||||
const wsProto = location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
const wsUrl = wsProto + '://' + location.host + basePath(location.pathname);
|
||||
|
||||
function createWebsocket(topologyUrl, optionsQuery) {
|
||||
if (socket) {
|
||||
socket.onclose = null;
|
||||
|
||||
31
client/app/styles/contrast.less
Normal file
31
client/app/styles/contrast.less
Normal file
@@ -0,0 +1,31 @@
|
||||
@import "main";
|
||||
|
||||
@background-color: lighten(@primary-color, 75%);
|
||||
@background-lighter-color: lighten(@background-color, 10%);
|
||||
@background-darker-color: darken(@background-color, 20%);
|
||||
@background-darker-secondary-color: darken(@background-color, 15%);
|
||||
@background-dark-color: @primary-color;
|
||||
@text-color: darken(@primary-color, 20%);
|
||||
@text-secondary-color: lighten(@text-color, 10%);
|
||||
@text-tertiary-color: lighten(@text-color, 20%);
|
||||
@border-light-color: lighten(@text-color, 50%);
|
||||
@text-darker-color: darken(@text-color, 20%);
|
||||
@white: @background-lighter-color;
|
||||
|
||||
@node-opacity-blurred: 0.6;
|
||||
@node-highlight-fill-opacity: 0.3;
|
||||
@node-highlight-stroke-opacity: 0.5;
|
||||
@node-highlight-stroke-width: 3px;
|
||||
@node-border-stroke-width: 6px;
|
||||
@node-pseudo-border-stroke-width: 2px;
|
||||
@node-pseudo-opacity: 1;
|
||||
@edge-highlight-opacity: 0.3;
|
||||
@edge-opacity-blurred: 0;
|
||||
@edge-opacity: 0.5;
|
||||
@edge-link-stroke-width: 3px;
|
||||
|
||||
@btn-opacity-default: 1;
|
||||
@btn-opacity-hover: 1;
|
||||
@btn-opacity-selected: 1;
|
||||
|
||||
@link-opacity-default: 1;
|
||||
@@ -27,7 +27,6 @@
|
||||
@background-darker-color: darken(@background-color, 8%);
|
||||
@background-darker-secondary-color: darken(@background-color, 4%);
|
||||
@background-dark-color: @primary-color;
|
||||
@background-medium-color: lighten(@background-dark-color, 55%);
|
||||
@text-color: lighten(@primary-color, 10%);
|
||||
@text-secondary-color: lighten(@primary-color, 27%);
|
||||
@text-tertiary-color: lighten(@primary-color, 50%);
|
||||
@@ -40,6 +39,24 @@
|
||||
|
||||
@terminal-header-height: 34px;
|
||||
|
||||
@node-opacity-blurred: 0.25;
|
||||
@node-highlight-fill-opacity: 0.1;
|
||||
@node-highlight-stroke-opacity: 0.4;
|
||||
@node-highlight-stroke-width: 1px;
|
||||
@node-border-stroke-width: 3px;
|
||||
@node-pseudo-border-stroke-width: 1px;
|
||||
@node-pseudo-opacity: 0.8;
|
||||
@edge-highlight-opacity: 0.1;
|
||||
@edge-opacity-blurred: 0.2;
|
||||
@edge-opacity: 0.5;
|
||||
@edge-link-stroke-width: 1px;
|
||||
|
||||
@btn-opacity-default: 0.7;
|
||||
@btn-opacity-hover: 1;
|
||||
@btn-opacity-selected: 0.9;
|
||||
|
||||
@link-opacity-default: 0.8;
|
||||
|
||||
/* add this class to truncate text with ellipsis, container needs width */
|
||||
.truncate {
|
||||
white-space: nowrap;
|
||||
@@ -77,12 +94,12 @@
|
||||
|
||||
.btn-opacity {
|
||||
.palable;
|
||||
opacity: 0.8;
|
||||
opacity: @btn-opacity-default;
|
||||
&-selected {
|
||||
opacity: 0.9;
|
||||
opacity: @btn-opacity-selected;
|
||||
}
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
opacity: @btn-opacity-hover;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +187,23 @@ h2 {
|
||||
&-label {
|
||||
text-transform: uppercase;
|
||||
margin: 0 0.25em;
|
||||
|
||||
&-icon {
|
||||
margin-left: 0.5em;
|
||||
padding: 4px 3px;
|
||||
color: @text-color;
|
||||
position: relative;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10%;
|
||||
&:hover {
|
||||
border: 1px solid @text-secondary-color;
|
||||
}
|
||||
span {
|
||||
font-size: 150%;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,10 +240,9 @@ h2 {
|
||||
.topologies-sub-item {
|
||||
// border: 1px solid @background-darker-secondary-color;
|
||||
color: @text-secondary-color;
|
||||
.palable;
|
||||
.btn-opacity;
|
||||
cursor: pointer;
|
||||
padding: 4px 8px;
|
||||
opacity: 0.7;
|
||||
border-radius: 4px;
|
||||
opacity: 0.8;
|
||||
margin-bottom: 3px;
|
||||
@@ -222,10 +255,6 @@ h2 {
|
||||
&-active {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.topologies-sub-item {
|
||||
@@ -280,7 +309,7 @@ h2 {
|
||||
transition: opacity .5s ease-in-out;
|
||||
|
||||
&.pseudo {
|
||||
opacity: 0.8;
|
||||
opacity: @node-pseudo-opacity;
|
||||
cursor: default;
|
||||
|
||||
.node-label {
|
||||
@@ -293,12 +322,12 @@ h2 {
|
||||
|
||||
.border {
|
||||
stroke: @text-tertiary-color;
|
||||
stroke-width: 1px;
|
||||
stroke-width: @node-pseudo-border-stroke-width;
|
||||
}
|
||||
}
|
||||
|
||||
&.blurred {
|
||||
opacity: 0.25;
|
||||
opacity: @node-opacity-blurred;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,14 +335,14 @@ h2 {
|
||||
transition: opacity .5s ease-in-out;
|
||||
|
||||
&.blurred {
|
||||
opacity: 0.2;
|
||||
opacity: @edge-opacity-blurred;
|
||||
}
|
||||
|
||||
.link {
|
||||
stroke: @text-secondary-color;
|
||||
stroke-width: 1px;
|
||||
stroke-width: @edge-link-stroke-width;
|
||||
fill: none;
|
||||
stroke-opacity: 0.5;
|
||||
stroke-opacity: @edge-opacity;
|
||||
}
|
||||
.shadow {
|
||||
stroke: @weave-blue;
|
||||
@@ -323,14 +352,14 @@ h2 {
|
||||
}
|
||||
&.highlighted {
|
||||
.shadow {
|
||||
stroke-opacity: 0.1;
|
||||
stroke-opacity: @edge-highlight-opacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
circle.border {
|
||||
stroke-width: 3px;
|
||||
stroke-width: @node-border-stroke-width;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
@@ -345,10 +374,10 @@ h2 {
|
||||
|
||||
circle.highlighted {
|
||||
fill: @weave-blue;
|
||||
fill-opacity: 0.1;
|
||||
fill-opacity: @node-highlight-fill-opacity;
|
||||
stroke: @weave-blue;
|
||||
stroke-width: 1px;
|
||||
stroke-opacity: 0.4;
|
||||
stroke-width: @node-highlight-stroke-width;
|
||||
stroke-opacity: @node-highlight-stroke-opacity;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -390,18 +419,16 @@ h2 {
|
||||
right: 8px;
|
||||
|
||||
span {
|
||||
.palable;
|
||||
.btn-opacity;
|
||||
padding: 4px 5px;
|
||||
margin-left: 2px;
|
||||
font-size: 110%;
|
||||
color: @white;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
border: 1px solid rgba(255, 255, 255, 0);
|
||||
border-radius: 10%;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
border-color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
@@ -440,34 +467,25 @@ h2 {
|
||||
|
||||
&-link {
|
||||
.truncate;
|
||||
.palable;
|
||||
.btn-opacity;
|
||||
display: inline-block;
|
||||
margin-right: 0.5em;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
opacity: 0.8;
|
||||
opacity: @link-opacity-default;
|
||||
max-width: 12em;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&-more {
|
||||
.palable;
|
||||
.btn-opacity;
|
||||
padding: 0 2px;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
font-size: 60%;
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: -5px;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,17 +498,15 @@ h2 {
|
||||
}
|
||||
|
||||
.node-control-button {
|
||||
.palable;
|
||||
.btn-opacity;
|
||||
padding: 6px;
|
||||
margin-left: 2px;
|
||||
font-size: 110%;
|
||||
color: @white;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
border: 1px solid rgba(255, 255, 255, 0);
|
||||
border-radius: 10%;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
border-color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
&-pending, &-pending:hover {
|
||||
@@ -534,8 +550,7 @@ h2 {
|
||||
margin-top: 48px;
|
||||
text-align: center;
|
||||
font-size: 48px;
|
||||
color: @background-medium-color;
|
||||
opacity: 0.7;
|
||||
color: @text-tertiary-color;
|
||||
}
|
||||
|
||||
&-section {
|
||||
@@ -557,7 +572,7 @@ h2 {
|
||||
text-align: center;
|
||||
|
||||
&-expand {
|
||||
.palable;
|
||||
.btn-opacity;
|
||||
margin: 4px 16px 0;
|
||||
border-top: 1px solid @border-light-color;
|
||||
text-transform: uppercase;
|
||||
@@ -565,15 +580,11 @@ h2 {
|
||||
color: @text-secondary-color;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
opacity: 1.0;
|
||||
}
|
||||
opacity: @link-opacity-default;
|
||||
}
|
||||
|
||||
&-overflow {
|
||||
.palable;
|
||||
.btn-opacity;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
@@ -584,10 +595,6 @@ h2 {
|
||||
position: relative;
|
||||
padding-bottom: 16px;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&-expand {
|
||||
text-transform: uppercase;
|
||||
font-size: 70%;
|
||||
@@ -728,14 +735,10 @@ h2 {
|
||||
}
|
||||
|
||||
&-link {
|
||||
.palable;
|
||||
.btn-opacity;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
opacity: @link-opacity-default;
|
||||
}
|
||||
|
||||
&-value, &-metric {
|
||||
@@ -917,6 +920,7 @@ h2 {
|
||||
cursor: pointer;
|
||||
font-size: 90%;
|
||||
margin-left: 0.5em;
|
||||
opacity: @link-opacity-default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
client/build/contrast.html
Normal file
20
client/build/contrast.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!doctype html>
|
||||
<html class="no-js">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Weave Scope</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<!--[if lt IE 10]>
|
||||
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||
<![endif]-->
|
||||
<div class="wrap">
|
||||
<div id="app"></div>
|
||||
</div>
|
||||
|
||||
<script src="vendors.js"></script>
|
||||
<script src="contrast-app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -19,7 +19,7 @@ var app = express();
|
||||
|
||||
|
||||
// Serve application file depending on environment
|
||||
app.get(/(app|terminal-app|vendors).js/, function(req, res) {
|
||||
app.get(/(app|contrast-app|terminal-app|vendors).js/, function(req, res) {
|
||||
var filename = req.originalUrl;
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
res.sendFile(__dirname + '/build' + filename);
|
||||
|
||||
@@ -28,6 +28,11 @@ module.exports = {
|
||||
'webpack-dev-server/client?http://localhost:4041',
|
||||
'webpack/hot/only-dev-server'
|
||||
],
|
||||
'contrast-app': [
|
||||
'./app/scripts/contrast-main',
|
||||
'webpack-dev-server/client?http://localhost:4041',
|
||||
'webpack/hot/only-dev-server'
|
||||
],
|
||||
'terminal-app': [
|
||||
'./app/scripts/terminal-main',
|
||||
'webpack-dev-server/client?http://localhost:4041',
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = {
|
||||
|
||||
entry: {
|
||||
app: './app/scripts/main',
|
||||
'contrast-app': './app/scripts/contrast-main',
|
||||
'terminal-app': './app/scripts/terminal-main',
|
||||
vendors: ['classnames', 'd3', 'dagre', 'flux', 'immutable',
|
||||
'lodash', 'page', 'react', 'react-dom', 'react-motion']
|
||||
|
||||
Reference in New Issue
Block a user