Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/app/notes/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { useState } from 'react';
import Sidebar from '@/components/Sidebar';
import NoteList from '@/components/NoteList';
import AddNoteButton from '@/components/AddNoteButton';
import Modal from '@/components/Modal';
import NoteForm from '@/components/NoteForm';

function NotesPage() {
const [notes, setNotes] = useState([]);
const [isModalOpen, setIsModalOpen] = useState(false);

const handleAddNote = (title: string, content: string) => {
setNotes([...notes, { title, date: new Date().toLocaleDateString() }]);
setIsModalOpen(false);
};

return (
<div className="flex">
<Sidebar activeItem="notes" />

<div className="flex-1 p-10">
<h1 className="text-4xl font-bold mb-6">Notes</h1>
<div className="bg-white shadow-md rounded p-6">
<NoteList notes={notes} />
<AddNoteButton onClick={() => setIsModalOpen(true)} />
</div>
</div>

<Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)}>
<NoteForm onSubmit={handleAddNote} />
</Modal>
</div>
);
}

export default NotesPage;
17 changes: 17 additions & 0 deletions src/components/AddNoteButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';

interface AddNoteButtonProps {
onClick: () => void;
}

function AddNoteButton({ onClick }: AddNoteButtonProps) {
return (
<button id="addNoteBtn" className="mt-6 bg-gray-200 rounded-full p-3 hover:bg-gray-300 focus:outline-none" onClick={onClick}>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 4v16m8-8H4"></path>
</svg>
</button>
);
}

export default AddNoteButton;
22 changes: 22 additions & 0 deletions src/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React, { ReactNode } from 'react';

interface ModalProps {
isOpen: boolean;
onClose: () => void;
children: ReactNode;
}

function Modal({ isOpen, onClose, children }: ModalProps) {
if (!isOpen) return null;

return (
<div className="modal" onClick={onClose}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
<span className="close" onClick={onClose}>&times;</span>
{children}
</div>
</div>
);
}

export default Modal;
37 changes: 37 additions & 0 deletions src/components/NoteForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { useState } from 'react';

interface NoteFormProps {
onSubmit: (title: string, content: string) => void;
}

function NoteForm({ onSubmit }: NoteFormProps) {
const [title, setTitle] = useState('');
const [content, setContent] = useState('');

const handleSubmit = (event: React.FormEvent) => {
event.preventDefault();
onSubmit(title, content);
setTitle('');
setContent('');
};

return (
<form id="addNoteForm" onSubmit={handleSubmit}>
<div className="mb-4">
<label htmlFor="noteTitle" className="block text-gray-700 text-sm font-bold mb-2">Title</label>
<input type="text" id="noteTitle" value={title} onChange={(e) => setTitle(e.target.value)} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" required />
</div>
<div className="mb-6">
<label htmlFor="noteContent" className="block text-gray-700 text-sm font-bold mb-2">Content</label>
<textarea id="noteContent" value={content} onChange={(e) => setContent(e.target.value)} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" rows="4" required></textarea>
</div>
<div className="flex items-center justify-between">
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="submit">
Add Note
</button>
</div>
</form>
);
}

export default NoteForm;
17 changes: 17 additions & 0 deletions src/components/NoteItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';

interface NoteItemProps {
title: string;
date: string;
}

function NoteItem({ title, date }: NoteItemProps) {
return (
<div className="flex justify-between items-center py-3 cursor-pointer">
<div className="text-lg">{title}</div>
<div className="text-sm text-gray-500">{date}</div>
</div>
);
}

export default NoteItem;
23 changes: 23 additions & 0 deletions src/components/NoteList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import NoteItem from '@/components/NoteItem';

interface Note {
title: string;
date: string;
}

interface NoteListProps {
notes: Note[];
}

function NoteList({ notes }: NoteListProps) {
return (
<div id="notesList" className="divide-y-2 divide-gray-100">
{notes.map((note, index) => (
<NoteItem key={index} title={note.title} date={note.date} />
))}
</div>
);
}

export default NoteList;
28 changes: 28 additions & 0 deletions src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import Link from 'next/link';

interface SidebarProps {
activeItem: string;
}

function Sidebar({ activeItem }: SidebarProps) {
return (
<div className="w-64 h-screen bg-white shadow-md">
<div className="flex items-center justify-center h-20 border-b">
<div className="rounded-full border-2 border-gray-300 w-12 h-12 flex items-center justify-center">
{/* User's initial, could be dynamically generated */}
O
</div>
<span className="ml-4 font-semibold">Gram Liu</span>
</div>
<div className="py-4">
{/* Menu Items */}
<Link href="/" passHref><a className={`menu-item block py-2.5 px-4 hover:bg-gray-200 ${activeItem === 'home' ? 'active' : ''}`}>Home</a></Link>
<Link href="/physics" passHref><a className={`menu-item block py-2.5 px-4 hover:bg-gray-200 ${activeItem === 'physics' ? 'active' : ''}`}>Physics</a></Link>
<Link href="/chemistry" passHref><a className={`menu-item block py-2.5 px-4 hover:bg-gray-200 ${activeItem === 'chemistry' ? 'active' : ''}`}>Chemistry</a></Link>
</div>
</div>
);
}

export default Sidebar;