Improved button handling and styling

This commit is contained in:
2019-09-02 20:01:00 +02:00
parent a7f4059311
commit 1af2ceb862
8 changed files with 65 additions and 54 deletions

View File

@@ -1,4 +1,4 @@
import styled, { keyframes } from "styled-components"; import styled, { keyframes, css } from "styled-components";
const fade = keyframes` const fade = keyframes`
from { transform: scale(.7) } from { transform: scale(.7) }
@@ -20,7 +20,12 @@ const Apple = styled.div.attrs(({ theme, zoom }) => ({
&:after { &:after {
content: "${props => (!props.died ? "🍎" : "🐛")}"; content: "${props => (!props.died ? "🍎" : "🐛")}";
display: inline-block; display: inline-block;
animation: ${fade} 1s ease-out alternate infinite; animation: ${props =>
props.died
? "none"
: css`
${fade} 1s ease-out alternate infinite
`};
} }
`; `;

View File

@@ -31,9 +31,14 @@ const SharedStyle = () => `
} }
`; `;
const ButtonWrapper = styled.div` const ButtonWrapper = styled.div.attrs(({ disabled }) => ({ tabIndex: disabled ? null : 0 }))`
position: relative; position: relative;
display: inline-block; display: inline-block;
&:focus,
&:hover {
outline: ${({ disabled }) => (!disabled ? "1px solid silver" : "none")};
}
`; `;
const StyledButton = styled.button` const StyledButton = styled.button`
@@ -49,13 +54,16 @@ const StyledNavLink = styled(NavLink)`
${SharedStyle} ${SharedStyle}
`; `;
export const Button = (props, refs) => { export const Button = props => {
const [hover, setHover] = React.useState(false); const [hover, setHover] = React.useState(false);
const updatedProps = { ...props }; const updatedProps = { ...props };
const disabled = props.disabled || props.toggle;
let tooltip = null; let tooltip = null;
if (props.onClick) { if (props.onClick) {
updatedProps.onClick = e => e.preventDefault() || props.onClick(); updatedProps.onKeyUp = e =>
!disabled && (e.which === 13 || e.which === 32) && (e.preventDefault() || props.onClick());
updatedProps.onClick = e => (!disabled && e.preventDefault()) || props.onClick();
} }
if (props.href) { if (props.href) {
@@ -72,13 +80,19 @@ export const Button = (props, refs) => {
if (props.icon) { if (props.icon) {
return ( return (
<ButtonWrapper onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}> <ButtonWrapper
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
onKeyUp={updatedProps.onKeyUp}
onClick={updatedProps.onClick}
disabled={disabled}>
<i <i
disabled={disabled}
onClick={updatedProps.onClick} onClick={updatedProps.onClick}
className={`fas fa-${props.icon} ${props.className}`} className={`fas fa-${props.icon} ${props.className}`}
style={{ display: "inline-block", fontSize: `${props.size || 1}rem` }} style={{ display: "inline-block", fontSize: `${props.size || 1}rem` }}
/> />
{tooltip} {!disabled && tooltip}
</ButtonWrapper> </ButtonWrapper>
); );
} }
@@ -98,6 +112,7 @@ export const IconButton = styled(Button)`
&:before { &:before {
text-shadow: 0 0 1px black, 1px 1px 3px #d0bfa3; text-shadow: 0 0 1px black, 1px 1px 3px #d0bfa3;
text-shadow: 0 0 1px gray, 0 0 1px #d0bfa3;
} }
`; `;

View File

@@ -41,9 +41,12 @@ const ThemeSelector = styled.select`
<polygon points="0,3 16,3 8,13" fill="${({ theme }) => theme.select.color.replace("#", "%23")}" /> <polygon points="0,3 16,3 8,13" fill="${({ theme }) => theme.select.color.replace("#", "%23")}" />
</svg>'); </svg>');
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: right 0.625rem center; background-position: right 0 center;
background-size: 1rem 1rem; background-size: 1rem 1rem;
outline-offset: 3px; outline-offset: 3px;
&:active,
&:focus,
&:hover { &:hover {
outline: 1px solid silver; outline: 1px solid silver;
} }

View File

@@ -25,15 +25,20 @@ const MenuButton = styled(NavLink)`
background: ${props => props.theme.header.menuButton.active.background}; background: ${props => props.theme.header.menuButton.active.background};
color: ${props => props.theme.header.menuButton.active.color}; color: ${props => props.theme.header.menuButton.active.color};
} }
&:active,
&:focus,
&:hover {
outline: 1px solid silver;
}
`; `;
const HeaderMenu = () => ( const HeaderMenu = () => (
<MenuPanel> <MenuPanel>
<MenuItem> <MenuItem>
<MenuButton to="/snake">Snake</MenuButton> <MenuButton to="/">Snake</MenuButton>
</MenuItem> </MenuItem>
<MenuItem> <MenuItem>
<MenuButton to="/" exact> <MenuButton to="/about" exact>
About About
</MenuButton> </MenuButton>
</MenuItem> </MenuItem>

View File

@@ -1,8 +1,14 @@
import React from "react"; import React from "react";
import { Route, Switch } from "react-router"; // react-router v4/v5 import { Route, Switch } from "react-router";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { hot } from "react-hot-loader/root"; import { hot } from "react-hot-loader/root";
import { MODULE_NAME as UI_MODULE_NAME } from "../redux/ui.js";
import { ThemeProvider } from "styled-components";
import { themes } from "../theming/theme.js";
import GlobalStyle from "../theming/GlobalStyle.js";
/* Containers */ /* Containers */
import Header from "./Header"; import Header from "./Header";
import Footer from "./Footer"; import Footer from "./Footer";
@@ -10,20 +16,26 @@ import Page from "../components/Page";
import Home from "./Home"; import Home from "./Home";
import Snake from "./Snake"; import Snake from "./Snake";
const App = ({ title, onNewTitle, getKeyboards, keyboards }) => ( const App = ({ theme }) => (
<React.Fragment> <ThemeProvider theme={themes[theme]}>
<Header /> <React.Fragment>
<Page> <GlobalStyle />
<Switch> <Header />
<Route exact path="/" component={Home} /> <Page>
<Route path="/snake" exact component={Snake} /> <Switch>
</Switch> <Route exact path="/" component={Snake} />
</Page> <Route path="/snake" exact component={Snake} />
<Footer /> <Route path="/about" exact component={Home} />
</React.Fragment> </Switch>
</Page>
<Footer />
</React.Fragment>
</ThemeProvider>
); );
const mapState = () => ({}); const mapState = state => ({
theme: state[UI_MODULE_NAME].theme || "light"
});
const mapActions = {}; const mapActions = {};

View File

@@ -1,27 +0,0 @@
import React from "react";
import { connect } from "react-redux";
import { hot } from "react-hot-loader/root";
import { MODULE_NAME as UI_MODULE_NAME } from "../redux/ui.js";
import { ThemeProvider } from "styled-components";
import { themes } from "../theming/theme.js";
import GlobalStyle from "../theming/GlobalStyle.js";
const Document = ({ theme, children }) => (
<ThemeProvider theme={themes[theme]}>
<React.Fragment>
<GlobalStyle />
{children}
</React.Fragment>
</ThemeProvider>
);
const ConnectedDocument = connect(
state => ({
theme: state[UI_MODULE_NAME].theme || "light"
}),
{}
)(Document);
export default (process.env.NODE_ENV === "development" ? hot(ConnectedDocument) : ConnectedDocument);
// export default (process.env.NODE_ENV === "development" ? hot(Document) : Document);

View File

@@ -7,7 +7,6 @@ import { createStore } from "./redux/store";
import { initSnake } from "./redux/snake"; import { initSnake } from "./redux/snake";
import { keyPress } from "./redux/game"; import { keyPress } from "./redux/game";
import Document from "./containers/Document.js";
import App from "./containers/App.js"; import App from "./containers/App.js";
const store = createStore(); const store = createStore();
@@ -16,9 +15,7 @@ window.store = store;
ReactDOM.render( ReactDOM.render(
<Provider store={store}> <Provider store={store}>
<ConnectedRouter history={store.history}> <ConnectedRouter history={store.history}>
<Document> <App />
<App />
</Document>
</ConnectedRouter> </ConnectedRouter>
</Provider>, </Provider>,
document.getElementById("root") document.getElementById("root")

View File

@@ -101,6 +101,7 @@ module.middleware(INIT, (dispatch, { loopId }) => {
module.middleware( module.middleware(
KEY_PRESS, KEY_PRESS,
(dispatch, { keyPressSubscribers = [], fps }, { key, altKey, ctrlKey, metaKey, shiftKey }) => { (dispatch, { keyPressSubscribers = [], fps }, { key, altKey, ctrlKey, metaKey, shiftKey }) => {
console.log("key", key);
keyPressSubscribers.forEach(subscriber => dispatch({ type: subscriber, key, altKey, ctrlKey, metaKey, shiftKey })); keyPressSubscribers.forEach(subscriber => dispatch({ type: subscriber, key, altKey, ctrlKey, metaKey, shiftKey }));
if (key === keys.PLUS || key === keys.EQUAL) { if (key === keys.PLUS || key === keys.EQUAL) {