7 - Creating Notes
7.1 Add Button

Add Button

In this step we will work on the note create functionality, which will be built out in it's own separate component, wrapping the Plus icon

Add Component

Create a new component called components/AddButton.jsx

We'll create the Plus icon in the next step.

AddButton.jsx
import Plus from "../icons/Plus";
 
const AddButton = () => {
    return (
        <div id="add-btn">
            <Plus />
        </div>
    );
};

Plus icon

Create the folling icon component inside of src/icons/Plus.jsx

Plus.jsx
const Plus = ({ size = "24", color = "#FFFFFF" }) => {
    return (
        <svg
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            width={size}
            height={size}
            stroke={color}
            fill="none"
            strokeWidth="2.5"
        >
            <path strokeLinecap="round" d="M18 12H6M12 6v12"></path>
        </svg>
    );
};

Controls panel

Our <AddButton/> will be place inside of another component called src/components/Controls.

Controls.jsx
import AddButton from "./AddButton";
 
const Controls = () => {
    return (
        <div id="controls">
            <AddButton />
        </div>
    );
};
 
export default Controls;

Add the Controls component inside of NotesPage.jsx. This item will have a fixed position, so where we place this is not particularly important.

NotesPage.jsx
<div>
    {notes.map((note) => (
       //...
    ))}
    <Controls />
</div>

Add CSS to controls and button

index.css
#controls {
    display: flex;
    flex-direction: column;
    gap: 1em;
    align-items: center;
    position: fixed;
    left: 1em;
    top: 50%;
    transform: translateY(-50%);
    background-color: #35363e;
    padding: 1em 1em;
    border-radius: 40px;
 
    box-shadow: 0 1px 1px hsl(0deg 0% 0% / 0.075), 0 2px 2px hsl(0deg 0% 0% /
                    0.075), 0 4px 4px hsl(0deg 0% 0% / 0.075), 0 8px 8px hsl(0deg
                    0% 0% / 0.075), 0 16px 16px hsl(0deg 0% 0% / 0.075);
    z-index: 10000;
}
 
#add-btn {
    background-color: rgba(107, 107, 107, 1);
    display: flex;
    justify-content: center;
    align-items: center;
    height: 40px;
    width: 40px;
    border-radius: 50%;
    cursor: pointer;
    transition: 0.3s;
}
 
#add-btn:hover {
    height: 45px;
    width: 45px;
}

Note color options

Each note will have 4 different color options. Let's store these options and their values in a separate file called src/assets/colors.json

We will reference the first color in this array as the default note color when a new note is added.

colors.json
[
    {
        "id": "color-yellow",
        "colorHeader": "#FFEFBE",
        "colorBody": "#FFF5DF",
        "colorText": "#18181A"
    },
    {
        "id": "color-green",
        "colorHeader": "#AFDA9F",
        "colorBody": "#BCDEAF",
        "colorText": "#18181A"
    },
    {
        "id": "color-blue",
        "colorHeader": "#9BD1DE",
        "colorBody": "#A6DCE9",
        "colorText": "#18181A"
    },
    {
        "id": "color-purple",
        "colorHeader": "#FED0FD",
        "colorBody": "#FEE5FD",
        "colorText": "#18181A"
    }
]

addNote method

To add a note, we will refence the first index in the colors array, as well as a default starting position for our x & y position.

This data will be pass along as the payload in the create method, as a new note is added to our database.

AddButton.jsx
import colors from "../assets/colors.json";
 
const AddButton = () => {
    const startingPos = useRef(10);
 
    const addNote = async () => {
        const payload = {
            position: JSON.stringify({
                x: startingPos.current,
                y: startingPos.current,
            }),
            colors: JSON.stringify(colors[0]),
        };
 
        const response = await db.notes.create(payload);
    };
 
    return (
        <div id="add-btn" onClick={addNote}>
            <Plus />
        </div>
    );
};

Update context state

Once a note is added, we will reference our notes state and add the new note to our current state.

As a note is added we will also increment the starting position to ensure that the next note wont overlap the previously created note.

AddButton
import { useContext } from "react";
import { NotesContext } from "../context/NotesContext";
 
const AddButton = () => {
    const { setNotes } = useContext(NotesContext);
    //...
    const addNote = async () => {
            const payload = {
                //..
            };
 
            startingPos.current += 10;
 
            const response = await db.notes.create(payload);
            setNotes((prevState) => [response, ...prevState]);
    };
 

Staring zIndex

To ensure a new note is always visible, lets call the setZIndex method with the useEffect hook inside of our <NoteCard/> component.

NoteCard.jsx
useEffect(() => {
    autoGrow(textAreaRef);
    setZIndex(cardRef.current);
}, []);