Skip to content

Commit

Permalink
Add Chords feature (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
cyrilgourgouillon authored Nov 24, 2023
1 parent 1f34336 commit 5485d25
Show file tree
Hide file tree
Showing 21 changed files with 206 additions and 38 deletions.
21 changes: 18 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import { ChakraProvider } from "@chakra-ui/react";
import { NotesPage } from "./pages";
import { Button, ChakraProvider } from "@chakra-ui/react";
import { ChordsPage, NotesPage } from "./pages";
import { AppPages } from "./config";
import { useState } from "react";

const App = () => {
const [selectedPage, setSelectedPage] = useState(AppPages.notes);

return (
<ChakraProvider>
<div className="h-screen flex flex-col items-center justify-between">
<NotesPage />
{selectedPage === AppPages.notes && (
<Button variant="ghost" colorScheme="purple" onClick={() => setSelectedPage(AppPages.chords)}>
Switch to chords
</Button>
)}
{selectedPage === AppPages.chords && (
<Button variant="ghost" colorScheme="blue" onClick={() => setSelectedPage(AppPages.notes)}>
Switch to notes
</Button>
)}
{selectedPage === AppPages.notes && <NotesPage />}
{selectedPage === AppPages.chords && <ChordsPage />}
<div className="mb-5">
{"Made with ❤️ by "}
<a
Expand Down
12 changes: 12 additions & 0 deletions src/components/ChordsList/ChordsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Chord } from "../../config";
import { chordToString } from "../../services/chordService";

export const ChordsList = ({ chords }: { chords: Chord[] }) => {
return (
<div className="flex flex-col md:flex-row md:gap-7 text-[35px] md:text-[75px] mb-6 font-bold">
{chords.map((chord: Chord, index: number) => (
<div key={index}>{chordToString(chord)}</div>
))}
</div>
);
};
1 change: 1 addition & 0 deletions src/components/ChordsList/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ChordsList';
4 changes: 3 additions & 1 deletion src/components/NotesList/NotesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export const NotesList = ({
}) => {
return (
<>
<div className="text-[25px] md:text-[25px] font-bold text-neutral-500">{GuitarStringDecorator}</div>
<div className="text-[25px] md:text-[25px] font-bold text-neutral-500">
{GuitarStringDecorator}
</div>
<div className="flex flex-col md:flex-row md:gap-7 text-[35px] md:text-[75px] mb-6 font-bold">
{notes.map((note: Note, index: number) => (
<div key={index}>{note}</div>
Expand Down
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './NotesList';
export * from './ChordsList';
4 changes: 4 additions & 0 deletions src/config/AppPages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum AppPages {
notes = "Notes",
chords = "Chords",
}
17 changes: 17 additions & 0 deletions src/config/Chords.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Note } from ".";

export enum ChordsType {
Major = "",
Minor = "m",
MajorSeventh = "maj7",
MinorSeventh = "min7",
}

export type ChordType = keyof typeof ChordsType;

export const chords = Object.values(ChordsType) as unknown as ChordType[];

export type Chord = {
note: Note;
chordType: ChordType;
};
16 changes: 9 additions & 7 deletions src/config/GuitarStrings.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
export enum GuitarStrings {
String1 = 'String 1',
String2 = 'String 2',
String3 = 'String 3',
String4 = 'String 4',
String5 = 'String 5',
String6 = 'String 6',
String1 = "String 1",
String2 = "String 2",
String3 = "String 3",
String4 = "String 4",
String5 = "String 5",
String6 = "String 6",
}

export type GuitarString = keyof typeof GuitarStrings;

export const guitarStrings = Object.values(GuitarStrings) as unknown as GuitarString[];
export const guitarStrings = Object.values(
GuitarStrings
) as unknown as GuitarString[];
34 changes: 17 additions & 17 deletions src/config/Notes.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
export enum Notes {
C = 'C',
Csharp = 'C#',
Dbemol = 'Db',
D = 'D',
Dsharp = 'D#',
Ebemol = 'Eb',
E = 'E',
F = 'F',
Fsharp = 'F#',
Gbemol = 'Gb',
G = 'G',
Gsharp = 'G#',
Abemol = 'Ab',
A = 'A',
Asharp = 'A#',
Bbemol = 'Bb',
B = 'B',
C = "C",
Csharp = "C#",
Dbemol = "Db",
D = "D",
Dsharp = "D#",
Ebemol = "Eb",
E = "E",
F = "F",
Fsharp = "F#",
Gbemol = "Gb",
G = "G",
Gsharp = "G#",
Abemol = "Ab",
A = "A",
Asharp = "A#",
Bbemol = "Bb",
B = "B",
}

export type Note = keyof typeof Notes;
Expand Down
3 changes: 3 additions & 0 deletions src/config/constants/chords.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const DEFAULT_NUMBER_OF_CHORD = 3;
export const CHORDS_LIST_MAX = 3;
export const CHORDS_LIST_MIN = 1;
1 change: 1 addition & 0 deletions src/config/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './notes';
export * from './chords';
6 changes: 4 additions & 2 deletions src/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './Notes';
export * from './GuitarStrings';
export * from "./Notes";
export * from "./GuitarStrings";
export * from "./Chords";
export * from "./AppPages";
69 changes: 69 additions & 0 deletions src/pages/ChordsPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useState } from "react";
import { Button, IconButton } from "@chakra-ui/react";

import { FaPlus, FaMinus } from "react-icons/fa";

import { ChordsList } from "../components";

import { getListOfRandomChords, isValidChordCountList } from "../services";
import {
DEFAULT_NUMBER_OF_CHORD,
CHORDS_LIST_MAX,
CHORDS_LIST_MIN,
} from "../config/constants";

export const ChordsPage = () => {
const [chords, setChords] = useState(
getListOfRandomChords(DEFAULT_NUMBER_OF_CHORD)
);

const [numberOfChordDisplayed, setNumberOfChordDisplayed] = useState(
DEFAULT_NUMBER_OF_CHORD
);

const handleGetRandomChordOnClick = () => {
setChords(getListOfRandomChords(numberOfChordDisplayed));
};

const handleChangeNumberOfChordDisplayed = (step: number) => {
setNumberOfChordDisplayed((prevState: number) => {
const value = prevState + step;
if (isValidChordCountList(value)) {
return value;
}
return prevState;
});
};

return (
<div className="h-full flex flex-col items-center justify-center">
<div className="text-lg font-semibold mb-10">RANDOM CHORDS GENERATOR</div>
<div className="w-screen flex items-center justify-center">
<div className="flex flex-col items-center">
<ChordsList chords={chords} />
<div className="flex flex-col gap-1">
<div className="flex gap-1">
<IconButton
aria-label="minus"
icon={<FaMinus />}
variant="outline"
onClick={() => handleChangeNumberOfChordDisplayed(-1)}
disabled={numberOfChordDisplayed === CHORDS_LIST_MIN}
/>
<Button variant="outline" onClick={handleGetRandomChordOnClick}>
Generate list of {numberOfChordDisplayed} chords
</Button>
<IconButton
aria-label="plus"
icon={<FaPlus />}
variant="outline"
onClick={() => handleChangeNumberOfChordDisplayed(1)}
disabled={numberOfChordDisplayed === CHORDS_LIST_MAX}
/>
</div>
</div>
</div>
</div>
</div>
);
};
4 changes: 2 additions & 2 deletions src/pages/NotesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { FaPlus, FaMinus } from "react-icons/fa";
import { GuitarString, Note } from "../config";
import { NotesList } from "../components";

import { getListOfRandomNotes, getRandomString, isValidCountList } from "../services";
import { getListOfRandomNotes, getRandomString, isValidNoteCountList } from "../services";
import { DEFAULT_NUMBER_OF_NOTE, NOTES_LIST_MAX, NOTES_LIST_MIN } from "../config/constants";

export const NotesPage = () => {
Expand All @@ -32,7 +32,7 @@ export const NotesPage = () => {
const handleChangeNumberOfNoteDisplayed = (step: number) => {
setNumberOfNoteDisplayed((prevState: number) => {
const value = prevState + step;
if (isValidCountList(value)) {
if (isValidNoteCountList(value)) {
return value;
}
return prevState;
Expand Down
3 changes: 2 additions & 1 deletion src/pages/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './NotesPage';
export * from "./NotesPage";
export * from "./ChordsPage";
28 changes: 28 additions & 0 deletions src/services/chordService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { getRandomNote } from "./";
import { Chord, ChordType, chords } from "../config";
import { getRandomItemFrom } from "../utils/random";
import { CHORDS_LIST_MAX, CHORDS_LIST_MIN } from "../config/constants";

export const getRandomChordType = (): ChordType => {
return getRandomItemFrom(chords);
};

export const getRandomChord = (): Chord => {
return { note: getRandomNote(), chordType: getRandomChordType() } as Chord;
};

export const chordToString = (chord: Chord): string => {
return `${chord.note}${chord.chordType}`;
}

export const getListOfRandomChords = (count: number): Chord[] => {
const randomChords: Chord[] = [];
for(let i = 0; i < count; i++) {
randomChords.push(getRandomChord());
}
return randomChords;
};

export const isValidChordCountList = (count: number): boolean => {
return count >= CHORDS_LIST_MIN && count <= CHORDS_LIST_MAX
}
5 changes: 3 additions & 2 deletions src/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './noteService'
export * from './stringService'
export * from "./noteService";
export * from "./stringService";
export * from "./chordService";
7 changes: 6 additions & 1 deletion src/services/noteService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Note, notes } from "../config";
import { NOTES_LIST_MAX, NOTES_LIST_MIN } from "../config/constants";
import { getRandomItemFrom } from "../utils/random";
import { shuffle } from "../utils/shuffle";

export const getListOfRandomNotes = (count: number): Note[] => {
Expand All @@ -8,6 +9,10 @@ export const getListOfRandomNotes = (count: number): Note[] => {
return randomNotes.slice(undefined, count);
};

export const isValidCountList = (count: number): boolean => {
export const isValidNoteCountList = (count: number): boolean => {
return count >= NOTES_LIST_MIN && count <= NOTES_LIST_MAX
}

export const getRandomNote = (): Note => {
return getRandomItemFrom(notes);
};
3 changes: 2 additions & 1 deletion src/services/stringService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { GuitarString, guitarStrings } from "../config";
import { getRandomItemFrom } from "../utils/random";

export const getRandomString = (): GuitarString => {
return guitarStrings[Math.floor(Math.random()*guitarStrings.length)];
return getRandomItemFrom(guitarStrings);
};
3 changes: 3 additions & 0 deletions src/utils/random.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const getRandomItemFrom = <T>(arrary: T[]): T => {
return arrary[Math.floor(Math.random()*arrary.length)];
};
2 changes: 1 addition & 1 deletion src/utils/shuffle.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Note } from "../config/Notes";

export const shuffle = (array: Note[]): Note[] => {
const arrayCopy = [...array];
const arrayCopy = [...array];

return arrayCopy.sort(() => Math.random() - 0.5);
};

0 comments on commit 5485d25

Please sign in to comment.