|
- import React, { FC } from 'react'
- import * as PropTypes from 'prop-types'
-
- const propTypes = {
- tunings: PropTypes.arrayOf(PropTypes.number),
- frets: PropTypes.number,
- leftHanded: PropTypes.bool,
- }
-
- export type Props = PropTypes.InferProps<typeof propTypes>
-
- const PITCHES = 'C C# D D# E F F# G G# A A# B'.split(' ')
-
- const Fretboard: FC<Props> = ({ tunings = [64, 59, 55, 50, 45, 40], frets = 24, leftHanded = false }) => {
- if (!Array.isArray(tunings!)) {
- return null
- }
-
- const strings = tunings!.map(t => new Array(frets).fill(0).map((_, i) => t! + i + 1))
-
- return (
- <div
- style={{
- border: '0.0625rem solid',
- boxSizing: 'border-box',
- transform: leftHanded
- ? 'perspective(6rem) rotateY(2deg) scaleX(1.375)'
- : 'perspective(6rem) rotateY(-2deg) scaleX(1.375)',
- transformOrigin: leftHanded ? 'left' : 'right',
- }}
- >
- {strings!.map((pitches, stringNumber) => (
- <div
- style={{
- display: 'flex',
- flexDirection: leftHanded ? 'row-reverse' : 'row',
- }}
- >
- <div
- style={{
- display: 'flex',
- flexDirection: leftHanded ? 'row-reverse' : 'row',
- width: '5rem',
- height: '1rem',
- padding: 0,
- boxSizing: 'border-box',
- }}
- >
- <input
- type="number"
- style={{
- display: 'block',
- width: '3rem',
- height: '1rem',
- padding: 0,
- boxSizing: 'border-box',
- }}
- defaultValue={tunings[stringNumber]!}
- min={0}
- max={127}
- />
- <span
- style={{
- display: 'block',
- width: '2rem',
- height: '1rem',
- textAlign: leftHanded ? 'left' : 'right',
- }}
- >
- {PITCHES[tunings[stringNumber]! % 12]}
- {Math.floor(tunings[stringNumber]! / 12)}
- </span>
- </div>
- <div
- style={{
- display: 'block',
- position: 'relative',
- width: '1rem',
- height: '1rem',
- flexShrink: 0,
- padding: 0,
- borderWidth: '0 0.0625rem',
- borderStyle: 'none solid',
- }}
- >
- <button
- type="button"
- style={{
- position: 'relative',
- display: 'block',
- width: '1rem',
- height: '1rem',
- flexShrink: 0,
- padding: 0,
- border: 0,
- backgroundColor: 'transparent',
- }}
- >
- <span
- style={{
- display: 'block',
- width: '100%',
- height: `${0.03125 + stringNumber * 0.03125}rem`,
- backgroundColor: 'currentColor',
- }}
- />
- </button>
- </div>
- {pitches.map((_, i) => (
- <div
- style={{
- width: `${(frets! - i + frets! / 2) * 100}%`,
- height: '1rem',
- position: 'relative',
- }}
- >
- {(i % 12 === 2 || i % 12 === 4 || i % 12 === 6 || i % 12 === 8 || i % 12 === 11) && stringNumber === 0 && (
- <div
- style={{
- position: 'absolute',
- top: 0,
- height: `${tunings.length * 100}%`,
- width: '100%',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'space-around',
- flexDirection: 'column',
- }}
- >
- <div
- style={{
- width: `${0.75 - i * (1 / 80)}rem`,
- height: `${0.75 - i * (1 / 256)}rem`,
- backgroundColor: 'currentColor',
- opacity: 0.5,
- borderRadius: '50%',
- }}
- />
- {i % 12 === 11 && (
- <div
- style={{
- width: `${0.75 - i * (1 / 80)}rem`,
- height: `${0.75 - i * (1 / 256)}rem`,
- backgroundColor: 'currentColor',
- opacity: 0.5,
- borderRadius: '50%',
- }}
- />
- )}
- </div>
- )}
- <button
- key={i}
- type="button"
- style={{
- position: 'relative',
- display: 'block',
- width: '100%',
- height: '1rem',
- padding: 0,
- borderWidth: '0 0.0625rem',
- borderStyle: 'none solid',
- backgroundColor: 'transparent',
- }}
- >
- <span
- style={{
- display: 'block',
- width: '100%',
- height: `${0.03125 + stringNumber * 0.03125}rem`,
- backgroundColor: 'currentColor',
- }}
- />
- </button>
- </div>
- ))}
- </div>
- ))}
- </div>
- )
- }
-
- Fretboard.propTypes = propTypes
-
- export default Fretboard
|