|
const React = require('react'); |
|
const { useState, useEffect, useReducer } = require('react'); |
|
const { render, Box, Text, useInput, useApp, useFocus } = require('ink'); |
|
const useStdoutDimensions = require('ink-use-stdout-dimensions'); |
|
|
|
const Key = ({ children, onSelect }) => { |
|
const { isFocused } = useFocus(); |
|
useInput((input, key) => { |
|
if (key.return && isFocused) { |
|
onSelect(); |
|
} |
|
}); |
|
|
|
return ( |
|
<Box |
|
borderColor={isFocused ? 'greenBright' : null} |
|
width={5} |
|
height={3} |
|
borderStyle="single" |
|
alignItems="center" |
|
justifyContent="center" |
|
> |
|
<Text>{children}</Text> |
|
</Box> |
|
); |
|
}; |
|
|
|
const CALCULATOR_TYPES = { |
|
INPUT: 'input', |
|
ADD: 'add', |
|
SUB: 'sub', |
|
DIV: 'div', |
|
MULT: 'mult', |
|
RESULT: 'result', |
|
CLEAR: 'clear', |
|
}; |
|
|
|
const initialState = { |
|
currentInput: '', |
|
currentResult: 0, |
|
currentOperation: CALCULATOR_TYPES.CLEAR, |
|
gatheringInput: true, |
|
}; |
|
|
|
function reducerFunction(state, action) { |
|
if (action.type === CALCULATOR_TYPES.CLEAR) { |
|
return initialState; |
|
} |
|
|
|
if (action.type === CALCULATOR_TYPES.INPUT && state.gatheringInput) { |
|
return { ...state, currentInput: state.currentInput + action.value }; |
|
} |
|
|
|
if (action.type === CALCULATOR_TYPES.ADD) { |
|
const currentInputAsNumber = parseFloat(state.currentInput); |
|
return { |
|
...state, |
|
currentInput: '', |
|
currentResult: state.currentResult + currentInputAsNumber, |
|
currentOperation: action.type, |
|
}; |
|
} |
|
|
|
if (action.type === CALCULATOR_TYPES.RESULT) { |
|
const currentInputAsNumber = parseFloat(state.currentInput); |
|
const currentResult = state.currentResult + currentInputAsNumber; |
|
return { |
|
...state, |
|
currentInput: currentResult.toString(), |
|
currentResult: currentResult, |
|
currentOperation: action.type, |
|
gatheringInput: false, |
|
}; |
|
} |
|
return state; |
|
} |
|
|
|
function toSymbol(op) { |
|
switch (op) { |
|
case CALCULATOR_TYPES.ADD: |
|
return '+'; |
|
case CALCULATOR_TYPES.SUB: |
|
return '-'; |
|
case CALCULATOR_TYPES.DIV: |
|
return '/'; |
|
case CALCULATOR_TYPES.MULT: |
|
return '*'; |
|
case CALCULATOR_TYPES.RESULT: |
|
return '='; |
|
case CALCULATOR_TYPES.CLEAR: |
|
return ' '; |
|
} |
|
} |
|
|
|
const App = () => { |
|
const [width, height] = useStdoutDimensions(); |
|
const [state, dispatch] = useReducer(reducerFunction, initialState); |
|
const { exit } = useApp(); |
|
|
|
const add = () => { |
|
dispatch({ type: CALCULATOR_TYPES.ADD }); |
|
}; |
|
const sub = () => { |
|
dispatch({ type: CALCULATOR_TYPES.SUB }); |
|
}; |
|
const div = () => { |
|
dispatch({ type: CALCULATOR_TYPES.DIV }); |
|
}; |
|
const result = () => { |
|
dispatch({ type: CALCULATOR_TYPES.RESULT }); |
|
}; |
|
const mult = () => { |
|
dispatch({ type: CALCULATOR_TYPES.MULT }); |
|
}; |
|
|
|
useInput((input, key) => { |
|
if (input === 'q') { |
|
exit(0); |
|
} else if (input.match(/[\d\.]/)) { |
|
if (input === '.' && state.currentInput.includes('.')) { |
|
return; |
|
} |
|
dispatch({ type: CALCULATOR_TYPES.INPUT, value: input }); |
|
} else if (key.escape) { |
|
dispatch({ type: CALCULATOR_TYPES.CLEAR }); |
|
} |
|
}); |
|
|
|
return ( |
|
<Box |
|
flexDirection="column" |
|
width={width} |
|
alignItems="center" |
|
justifyContent="center" |
|
height={height} |
|
margin={1} |
|
padding={2} |
|
> |
|
<Box flexDirection="column" borderStyle="double" width={31}> |
|
<Box height={3} paddingRight={1}> |
|
<Box height={3} alignItems="center"> |
|
<Text>{toSymbol(state.currentOperation)}</Text> |
|
</Box> |
|
<Box height={3} flexGrow={1} borderStyle="single"> |
|
<Text>{state.currentInput}</Text> |
|
</Box> |
|
</Box> |
|
<Box |
|
marginTop={1} |
|
width="100%" |
|
flexDirection="row" |
|
justifyContent="space-around" |
|
> |
|
<Key onSelect={add}>{'+'}</Key> |
|
<Key onSelect={sub}>{'-'}</Key> |
|
<Key onSelect={result}>{'='}</Key> |
|
<Key onSelect={div}>{'/'}</Key> |
|
<Key onSelect={mult}>{'*'}</Key> |
|
</Box> |
|
</Box> |
|
</Box> |
|
); |
|
}; |
|
|
|
async function renderApp() { |
|
const { waitUntilExit } = render(<App />); |
|
|
|
await waitUntilExit(); |
|
console.log('Bye'); |
|
} |
|
|
|
module.exports = { renderApp }; |
Updated with BIG TEXT and GRADIENTS! https://gist.github.com/philnash/4c4a10b728cf558873e7cb5bbedc1e96