add Menu modal
This commit is contained in:
@@ -6,14 +6,15 @@ Alapatch currently only supports loading and saving patch files in the .SYSEX fo
|
|||||||
|
|
||||||
# Branch TODO List
|
# Branch TODO List
|
||||||
|
|
||||||
- [x] implement React Redux Correctly
|
- [x] implement React Redux Correctly
|
||||||
- [x] finish implementing for each component
|
- [x] finish implementing for each component
|
||||||
- [x] finish one timbre as an example
|
- [x] finish one timbre as an example
|
||||||
- [x] update state and components to handle multiple timbres
|
- [x] update state and components to handle multiple timbres
|
||||||
- [x] implement switching between currently viewed timbre
|
- [x] implement switching between currently viewed timbre
|
||||||
- [ ] make a home screen!
|
- [x] make a home screen!
|
||||||
- [ ] style components
|
- [ ] implement popup to confirm new patch if a patch is currently being worked on.
|
||||||
- [ ] merge with main branch
|
- [ ] style components
|
||||||
|
- [ ] merge with main branch
|
||||||
|
|
||||||
# Link to the MicroKORG Midi Implementation
|
# Link to the MicroKORG Midi Implementation
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
.App {
|
.App {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-logo {
|
.App-logo {
|
||||||
|
|||||||
+106
-7
@@ -1,21 +1,23 @@
|
|||||||
.menu,
|
.menu,
|
||||||
.menu-true,
|
.menu-true,
|
||||||
.menu-false {
|
.menu-false {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
background: white;
|
background: white;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 9999;
|
z-index: 99;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
min-width: 100vw;
|
min-width: 100vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-false {
|
.menu-false {
|
||||||
left: -100vw;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-true-animation {
|
.menu-true-animation {
|
||||||
@@ -83,16 +85,28 @@
|
|||||||
.menu-logo {
|
.menu-logo {
|
||||||
height: 40vmin;
|
height: 40vmin;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-title {
|
.menu-title {
|
||||||
color: #1c1d21;
|
color: #1c1d21;
|
||||||
font-family: 'Lato', sans-serif;
|
font-family: 'Lato', sans-serif;
|
||||||
font-weight: 700;
|
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
font-size: calc(10px + 10vmin);
|
|
||||||
margin: 0 0 0.5em 0;
|
margin: 0 0 0.5em 0;
|
||||||
}
|
}
|
||||||
|
h1 {
|
||||||
|
margin: 0.25em;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 0.85em;
|
||||||
|
font-size: 2.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0.25em;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1em;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-button,
|
.menu-button,
|
||||||
.menu-open-button {
|
.menu-open-button {
|
||||||
@@ -109,6 +123,12 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
outline: none;
|
outline: none;
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
|
-webkit-touch-callout: none; /* iOS Safari */
|
||||||
|
-webkit-user-select: none; /* Safari */
|
||||||
|
-khtml-user-select: none; /* Konqueror HTML */
|
||||||
|
-moz-user-select: none; /* Old versions of Firefox */
|
||||||
|
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
.menu-button:hover {
|
.menu-button:hover {
|
||||||
color: white;
|
color: white;
|
||||||
@@ -121,10 +141,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.menu-open-button {
|
.menu-open-button {
|
||||||
height: 1.5em;
|
z-index: 100;
|
||||||
|
height: 1.495em;
|
||||||
line-height: 0.9em;
|
line-height: 0.9em;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 0.13em 0.3em;
|
padding: 0em 0.3em;
|
||||||
color: #ef476f;
|
color: #ef476f;
|
||||||
border: 0.09em solid #ef476f;
|
border: 0.09em solid #ef476f;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -137,3 +158,81 @@
|
|||||||
.menu-open-button::before {
|
.menu-open-button::before {
|
||||||
content: '\2630';
|
content: '\2630';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
margin: auto;
|
||||||
|
height: 8em;
|
||||||
|
width: 14em;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 100;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-display {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-main {
|
||||||
|
background: white;
|
||||||
|
padding: 0.75em 0 1em;
|
||||||
|
border: solid 1pt slategrey;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
font-size: 0.75em;
|
||||||
|
line-height: 1.25em;
|
||||||
|
text-align: left;
|
||||||
|
margin: 0em 9em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-text {
|
||||||
|
flex-grow: 3;
|
||||||
|
margin: 0.5em 0em 1em 1.85em;
|
||||||
|
text-align: left;
|
||||||
|
line-height: 1.5em;
|
||||||
|
font-size: 0.65em;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-save,
|
||||||
|
.button-no-save,
|
||||||
|
.button-cancel {
|
||||||
|
width: 25%;
|
||||||
|
font-size: 0.5em;
|
||||||
|
margin: 0 0.5em;
|
||||||
|
border-radius: 0.2em;
|
||||||
|
padding: 0.35em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-save {
|
||||||
|
color: mediumseagreen;
|
||||||
|
border-color: mediumseagreen;
|
||||||
|
}
|
||||||
|
.button-save:hover {
|
||||||
|
background: mediumseagreen;
|
||||||
|
}
|
||||||
|
.button-no-save {
|
||||||
|
color: crimson;
|
||||||
|
border-color: crimson;
|
||||||
|
}
|
||||||
|
.button-no-save:hover {
|
||||||
|
background: crimson;
|
||||||
|
}
|
||||||
|
.button-cancel {
|
||||||
|
color: slategray;
|
||||||
|
border-color: grey;
|
||||||
|
}
|
||||||
|
.button-cancel:hover {
|
||||||
|
background: slategray;
|
||||||
|
}
|
||||||
|
|||||||
+68
-10
@@ -1,16 +1,56 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useCallback } from 'react';
|
||||||
import { useDispatch } from 'react-redux'; // probably temporarily here
|
import { useDispatch, useSelector } from 'react-redux'; // probably temporarily here
|
||||||
import { parameterRefreshAll } from '../timbre/parameters/parameterSlice'; // probably temporarily here
|
import {
|
||||||
|
parameterRefreshAll,
|
||||||
|
parameterFlipUnsaved,
|
||||||
|
} from '../timbre/parameters/parameterSlice'; // probably temporarily here
|
||||||
import logo from '../../1f3b9.svg';
|
import logo from '../../1f3b9.svg';
|
||||||
import './Menu.css';
|
import './Menu.css';
|
||||||
|
|
||||||
export default function MainMenu(props) {
|
// for things such as (do you want to save? or do you want to reset things?)
|
||||||
|
const Modal = ({ show, handleSave, handleNoSave, handleClose }) => {
|
||||||
|
const modalDisplay = show ? 'modal modal-display' : 'modal modal-hide';
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
return (
|
||||||
|
<div className={modalDisplay}>
|
||||||
|
<div className="modal-main">
|
||||||
|
<span className="modal-header">Save Changes</span>
|
||||||
|
<span className="modal-text">
|
||||||
|
Do you want to save your changes?
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
className="menu-button button-save"
|
||||||
|
onClick={handleSave}>
|
||||||
|
Save Changes
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="menu-button button-no-save"
|
||||||
|
onClick={handleNoSave}>
|
||||||
|
Don't Save
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="menu-button button-cancel"
|
||||||
|
onClick={handleClose}>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function MainMenu() {
|
||||||
|
const unsaved = useSelector((state) => state.parameters.unsaved);
|
||||||
const [open, setOpen] = useState({
|
const [open, setOpen] = useState({
|
||||||
className: '',
|
className: '',
|
||||||
openState: true,
|
openState: true,
|
||||||
});
|
});
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const unSavedUpdate = useCallback(() => dispatch(parameterFlipUnsaved), [
|
||||||
|
dispatch,
|
||||||
|
]);
|
||||||
|
|
||||||
const HandleClick = () => {
|
const HandleClick = () => {
|
||||||
setOpen({
|
setOpen({
|
||||||
className: open.openState
|
className: open.openState
|
||||||
@@ -27,28 +67,46 @@ export default function MainMenu(props) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const modalState = () => {
|
||||||
|
setShowModal(!showModal);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<Modal
|
||||||
|
show={showModal}
|
||||||
|
handleClose={modalState}
|
||||||
|
handleSave={() => {
|
||||||
|
modalState();
|
||||||
|
HandleClick(); // temporary while I implement the binary parsing stuff
|
||||||
|
}}
|
||||||
|
handleNoSave={() => {
|
||||||
|
dispatch(parameterRefreshAll());
|
||||||
|
modalState();
|
||||||
|
HandleClick();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
className={`menu ${open.className}`}
|
className={`menu ${open.className}`}
|
||||||
onAnimationEnd={AnimationEnd}>
|
onAnimationEnd={AnimationEnd}>
|
||||||
<img src={logo} className="menu-logo" alt="logo" />
|
<img src={logo} className="menu-logo" alt="logo" />
|
||||||
<header className="menu-title">Alapatch</header>
|
<header className="menu-title">
|
||||||
|
<h1>Alapatch</h1>
|
||||||
|
<h2>A microKORG Patch Editor</h2>
|
||||||
|
</header>
|
||||||
<div className="menu-button-container">
|
<div className="menu-button-container">
|
||||||
<button
|
<button
|
||||||
className="menu-button"
|
className="menu-button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
HandleClick();
|
!unsaved ? HandleClick() : modalState();
|
||||||
dispatch(parameterRefreshAll());
|
|
||||||
}}>
|
}}>
|
||||||
New Patch
|
New Patch
|
||||||
</button>
|
</button>
|
||||||
<button className="menu-button">Load Patch</button>
|
<button className="menu-button">Load Patch</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!open.openState && (
|
|
||||||
<button className="menu-open-button" onClick={HandleClick} />
|
<button className="menu-open-button" onClick={HandleClick} />
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -372,6 +372,7 @@ const defaultState = {
|
|||||||
target: 'Both',
|
target: 'Both',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
unsaved: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const parametersAdapter = createEntityAdapter({});
|
const parametersAdapter = createEntityAdapter({});
|
||||||
@@ -380,9 +381,14 @@ const parametersSlice = createSlice({
|
|||||||
name: 'parameters',
|
name: 'parameters',
|
||||||
initialState: parametersAdapter.getInitialState(defaultState),
|
initialState: parametersAdapter.getInitialState(defaultState),
|
||||||
reducers: {
|
reducers: {
|
||||||
parameterAdded: parametersAdapter.addOne,
|
parameterUpdated(state, action) {
|
||||||
parameterUpdated: parametersAdapter.updateOne,
|
parametersAdapter.updateOne(state, action.payload);
|
||||||
|
state.unsaved = true;
|
||||||
|
},
|
||||||
parameterRefreshAll: () => defaultState,
|
parameterRefreshAll: () => defaultState,
|
||||||
|
parameterFlipUnsaved(state) {
|
||||||
|
state.unsaved = !state.unsaved;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -397,6 +403,7 @@ export const {
|
|||||||
parameterAdded,
|
parameterAdded,
|
||||||
parameterUpdated,
|
parameterUpdated,
|
||||||
parameterRefreshAll,
|
parameterRefreshAll,
|
||||||
|
parameterFlipUnsaved,
|
||||||
} = parametersSlice.actions;
|
} = parametersSlice.actions;
|
||||||
|
|
||||||
export default parametersSlice.reducer;
|
export default parametersSlice.reducer;
|
||||||
|
|||||||
Reference in New Issue
Block a user