Add theme toggle
This commit is contained in:
@@ -1,6 +1,13 @@
|
|||||||
import { ActionTypes } from '../reducers'
|
import { ActionTypes, AppState, CustomAction } from '../reducers'
|
||||||
|
import { Dispatch } from 'redux';
|
||||||
|
|
||||||
export const showError = (error?: string) => ({
|
export const showError = (error?: string) => ({
|
||||||
error,
|
error,
|
||||||
type: ActionTypes.showError,
|
type: ActionTypes.showError,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const toggleTheme = () => (dispatch: Dispatch<CustomAction>, getState: () => AppState) => {
|
||||||
|
dispatch({
|
||||||
|
type: getState().globalState.theme === 'light' ? ActionTypes.setDarkTheme : ActionTypes.setLightTheme,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -106,12 +106,13 @@ class BrokerStatistics extends React.Component<Props, {}> {
|
|||||||
|
|
||||||
public renderStat(tree: q.Tree<TopicViewModel>, stat: Stats) {
|
public renderStat(tree: q.Tree<TopicViewModel>, stat: Stats) {
|
||||||
const node = tree.findNode(stat.topic)
|
const node = tree.findNode(stat.topic)
|
||||||
if (!node) {
|
if (!node || !node.message) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = (node.message && node.message.value) ? parseFloat(Base64Message.toUnicodeString(node.message.value)) : NaN
|
const str = node.message.value ? Base64Message.toUnicodeString(node.message.value) : ''
|
||||||
value = !isNaN(value) ? abbreviate(value) : value
|
let value = (node.message && node.message.value) ? parseFloat(str) : NaN
|
||||||
|
value = !isNaN(value) ? abbreviate(value) : str
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={stat.title}>
|
<div key={stat.title}>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import ChevronRight from '@material-ui/icons/ChevronRight'
|
|||||||
import { AppState } from '../reducers'
|
import { AppState } from '../reducers'
|
||||||
import { bindActionCreators } from 'redux'
|
import { bindActionCreators } from 'redux'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { settingsActions } from '../actions'
|
import { settingsActions, globalActions } from '../actions'
|
||||||
import { shell } from 'electron'
|
import { shell } from 'electron'
|
||||||
import { StyleRulesCallback, withStyles } from '@material-ui/core/styles'
|
import { StyleRulesCallback, withStyles } from '@material-ui/core/styles'
|
||||||
import { TopicOrder } from '../reducers/Settings'
|
import { TopicOrder } from '../reducers/Settings'
|
||||||
@@ -70,6 +70,7 @@ const styles: StyleRulesCallback = theme => ({
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
actions: typeof settingsActions
|
actions: typeof settingsActions
|
||||||
|
globalActions: typeof globalActions
|
||||||
autoExpandLimit: number
|
autoExpandLimit: number
|
||||||
classes: any
|
classes: any
|
||||||
highlightTopicUpdates: boolean
|
highlightTopicUpdates: boolean
|
||||||
@@ -77,6 +78,7 @@ interface Props {
|
|||||||
store?: any
|
store?: any
|
||||||
topicOrder: TopicOrder
|
topicOrder: TopicOrder
|
||||||
visible: boolean
|
visible: boolean
|
||||||
|
theme: 'light' | 'dark'
|
||||||
}
|
}
|
||||||
|
|
||||||
class Settings extends React.Component<Props, {}> {
|
class Settings extends React.Component<Props, {}> {
|
||||||
@@ -112,6 +114,7 @@ class Settings extends React.Component<Props, {}> {
|
|||||||
{this.renderNodeOrder()}
|
{this.renderNodeOrder()}
|
||||||
{this.renderHighlightTopicUpdates()}
|
{this.renderHighlightTopicUpdates()}
|
||||||
{this.selectTopicsOnMouseOver()}
|
{this.selectTopicsOnMouseOver()}
|
||||||
|
{this.toggleTheme()}
|
||||||
</div>
|
</div>
|
||||||
<Tooltip placement="top" title="App Author">
|
<Tooltip placement="top" title="App Author">
|
||||||
<Typography className={classes.author} onClick={this.openGithubPage}>
|
<Typography className={classes.author} onClick={this.openGithubPage}>
|
||||||
@@ -173,6 +176,12 @@ class Settings extends React.Component<Props, {}> {
|
|||||||
return this.renderSwitch('Quick Preview', selectTopicWithMouseOver, toggle, 'Select topics on mouse over')
|
return this.renderSwitch('Quick Preview', selectTopicWithMouseOver, toggle, 'Select topics on mouse over')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private toggleTheme() {
|
||||||
|
const { globalActions, theme } = this.props
|
||||||
|
|
||||||
|
return this.renderSwitch('Theme', theme === 'light', globalActions.toggleTheme, 'Select a theme')
|
||||||
|
}
|
||||||
|
|
||||||
private renderAutoExpand() {
|
private renderAutoExpand() {
|
||||||
const { classes, autoExpandLimit } = this.props
|
const { classes, autoExpandLimit } = this.props
|
||||||
|
|
||||||
@@ -233,12 +242,14 @@ const mapStateToProps = (state: AppState) => {
|
|||||||
visible: state.settings.visible,
|
visible: state.settings.visible,
|
||||||
highlightTopicUpdates: state.settings.highlightTopicUpdates,
|
highlightTopicUpdates: state.settings.highlightTopicUpdates,
|
||||||
selectTopicWithMouseOver: state.settings.selectTopicWithMouseOver,
|
selectTopicWithMouseOver: state.settings.selectTopicWithMouseOver,
|
||||||
|
theme: state.globalState.theme,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: any) => {
|
const mapDispatchToProps = (dispatch: any) => {
|
||||||
return {
|
return {
|
||||||
actions: bindActionCreators(settingsActions, dispatch),
|
actions: bindActionCreators(settingsActions, dispatch),
|
||||||
|
globalActions: bindActionCreators(globalActions, dispatch),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ class Publish extends React.Component<Props, State> {
|
|||||||
private history() {
|
private history() {
|
||||||
const items = this.state.history.reverse().map(message => ({
|
const items = this.state.history.reverse().map(message => ({
|
||||||
title: message.topic,
|
title: message.topic,
|
||||||
value: message.payload,
|
value: message.payload || '',
|
||||||
}))
|
}))
|
||||||
|
|
||||||
return <History items={items} onClick={this.didSelectHistoryEntry} />
|
return <History items={items} onClick={this.didSelectHistoryEntry} />
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import * as ReactDOM from 'react-dom'
|
import * as ReactDOM from 'react-dom'
|
||||||
import App from './App'
|
import App from './App'
|
||||||
import Demo from './components/demo'
|
import Demo from './components/Demo'
|
||||||
import reducers from './reducers'
|
import reducers, { AppState } from './reducers'
|
||||||
import reduxThunk from 'redux-thunk'
|
import reduxThunk from 'redux-thunk'
|
||||||
import { applyMiddleware, compose, createStore } from 'redux'
|
import { applyMiddleware, compose, createStore } from 'redux'
|
||||||
import { batchDispatchMiddleware } from 'redux-batched-actions'
|
import { batchDispatchMiddleware } from 'redux-batched-actions'
|
||||||
import { createMuiTheme, MuiThemeProvider } from '@material-ui/core/styles'
|
import { createMuiTheme, MuiThemeProvider, Theme } from '@material-ui/core/styles'
|
||||||
import { Provider } from 'react-redux'
|
import { Provider, connect } from 'react-redux'
|
||||||
import './tracking'
|
import './tracking'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const composeEnhancers = /*(window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || */ compose
|
const composeEnhancers = /*(window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || */ compose
|
||||||
const store = createStore(
|
const store = createStore(
|
||||||
reducers,
|
reducers,
|
||||||
@@ -24,12 +21,6 @@ const store = createStore(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
const theme = createMuiTheme({
|
|
||||||
palette: {
|
|
||||||
type: 'dark',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const splash = document.getElementById('splash')
|
const splash = document.getElementById('splash')
|
||||||
if (splash) {
|
if (splash) {
|
||||||
@@ -38,12 +29,42 @@ setTimeout(() => {
|
|||||||
}
|
}
|
||||||
}, 300)
|
}, 300)
|
||||||
|
|
||||||
|
function createTheme(type: 'light' | 'dark') {
|
||||||
|
if (type === 'dark') {
|
||||||
|
return createMuiTheme({
|
||||||
|
palette: {
|
||||||
|
type: 'dark',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return createMuiTheme({
|
||||||
|
palette: {
|
||||||
|
type: 'light',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ApplicationRenderer(props: {theme: 'light' | 'dark'}) {
|
||||||
|
return (
|
||||||
|
<MuiThemeProvider theme={createTheme(props.theme)}>
|
||||||
|
<App />
|
||||||
|
<Demo />
|
||||||
|
</MuiThemeProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state: AppState) => {
|
||||||
|
return {
|
||||||
|
theme: state.globalState.theme,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Application = connect(mapStateToProps)(ApplicationRenderer)
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<MuiThemeProvider theme={theme}>
|
<Provider store={store}>
|
||||||
<Provider store={store}>
|
<Application />
|
||||||
<App />
|
</Provider>,
|
||||||
<Demo />
|
document.getElementById('app'),
|
||||||
</Provider>
|
|
||||||
</MuiThemeProvider>,
|
|
||||||
document.getElementById('app'),
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ import { settingsReducer, SettingsState } from './Settings'
|
|||||||
import { trackEvent } from '../tracking'
|
import { trackEvent } from '../tracking'
|
||||||
import { treeReducer, TreeState } from './Tree'
|
import { treeReducer, TreeState } from './Tree'
|
||||||
|
|
||||||
|
|
||||||
export enum ActionTypes {
|
export enum ActionTypes {
|
||||||
showUpdateNotification = 'SHOW_UPDATE_NOTIFICATION',
|
showUpdateNotification = 'SHOW_UPDATE_NOTIFICATION',
|
||||||
showUpdateDetails = 'SHOW_UPDATE_DETAILS',
|
showUpdateDetails = 'SHOW_UPDATE_DETAILS',
|
||||||
showError = 'SHOW_ERROR',
|
showError = 'SHOW_ERROR',
|
||||||
|
setDarkTheme = 'GLOBAL_SET_DARK_THEME',
|
||||||
|
setLightTheme = 'GLOBAL_SET_LIGHT_THEME',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CustomAction extends Action {
|
export interface CustomAction extends Action {
|
||||||
@@ -33,13 +34,15 @@ export interface GlobalState {
|
|||||||
showUpdateNotification?: boolean
|
showUpdateNotification?: boolean
|
||||||
showUpdateDetails: boolean
|
showUpdateDetails: boolean
|
||||||
error?: string
|
error?: string
|
||||||
|
theme: 'light' | 'dark'
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialBigState: GlobalState = {
|
const initialGlobalState: GlobalState = {
|
||||||
showUpdateDetails: false,
|
showUpdateDetails: false,
|
||||||
|
theme: 'dark',
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalState: Reducer<GlobalState | undefined, CustomAction> = (state = initialBigState, action) => {
|
const globalState: Reducer<GlobalState | undefined, CustomAction> = (state = initialGlobalState, action) => {
|
||||||
if (!state) {
|
if (!state) {
|
||||||
throw Error('No initial state')
|
throw Error('No initial state')
|
||||||
}
|
}
|
||||||
@@ -58,6 +61,18 @@ const globalState: Reducer<GlobalState | undefined, CustomAction> = (state = ini
|
|||||||
error: action.error,
|
error: action.error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ActionTypes.setDarkTheme:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
theme: 'dark',
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionTypes.setLightTheme:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
theme: 'light',
|
||||||
|
}
|
||||||
|
|
||||||
case ActionTypes.showUpdateDetails:
|
case ActionTypes.showUpdateDetails:
|
||||||
if (action.showUpdateDetails === undefined) {
|
if (action.showUpdateDetails === undefined) {
|
||||||
return state
|
return state
|
||||||
|
|||||||
Reference in New Issue
Block a user