diff --git a/app/components/Contact.js b/app/components/Contact.js
new file mode 100644
index 0000000..7426d07
--- /dev/null
+++ b/app/components/Contact.js
@@ -0,0 +1,74 @@
+"use client";
+import PropTypes from "prop-types";
+import Link from "next/link";
+import Image from "next/image";
+import EditButtons from "./EditButtons";
+
+export function ErrorState({ title, message }) {
+ return (
+
+
{title}
+
{message}
+
+ Back to Contacts
+
+
+ );
+}
+
+ErrorState.propTypes = {
+ title: PropTypes.string.isRequired,
+ message: PropTypes.string.isRequired,
+};
+
+function Contact({ contact, onDelete }) {
+ return (
+
+
+ {
+ e.target.src = "https://cdn-icons-png.flaticon.com/512/8847/8847419.png";
+ }}
+ />
+
+
+
+ {contact.name}
+
+
+
+ {contact.email}
+
+
+ {contact.phone_number || "—"}
+
+
+
+
+
+ );
+}
+
+Contact.propTypes = {
+ contact: PropTypes.shape({
+ id: PropTypes.number,
+ name: PropTypes.string,
+ email: PropTypes.string,
+ phone_number: PropTypes.string,
+ image_url: PropTypes.string,
+ }),
+ onDelete: PropTypes.func,
+};
+
+Contact.defaultProps = {
+ contact: {},
+ onDelete: () => {},
+};
+
+export default Contact;
diff --git a/app/components/ContactForm.js b/app/components/ContactForm.js
new file mode 100644
index 0000000..1d6f309
--- /dev/null
+++ b/app/components/ContactForm.js
@@ -0,0 +1,151 @@
+"use client";
+import PropTypes from "prop-types";
+import { useState } from "react";
+import Link from "next/link";
+import { useRouter } from "next/navigation";
+import { ContactAPI } from "../data/contactAPI";
+
+function ContactForm({
+ contact = { id: 0, name: "", email: "", phone_number: "", image_url: "" },
+}) {
+ const router = useRouter();
+ const [formData, setFormData] = useState({
+ name: contact.name || "",
+ email: contact.email || "",
+ phone_number: contact.phone_number || "",
+ image_url: contact.image_url || ""
+ });
+ const [errors, setErrors] = useState({});
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData(prev => ({
+ ...prev,
+ [name]: value
+ }));
+ // Clear error when user starts typing
+ if (errors[name]) {
+ setErrors(prev => ({ ...prev, [name]: "" }));
+ }
+ };
+
+ const validateForm = () => {
+ const newErrors = {};
+ if (!formData.name.trim()) newErrors.name = "Name is required";
+ if (!formData.email.trim()) newErrors.email = "Email is required";
+ if (!formData.phone_number.trim()) newErrors.phone_number = "Phone number is required";
+ return newErrors;
+ };
+
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ const validationErrors = validateForm();
+ setErrors(validationErrors);
+
+ if (Object.keys(validationErrors).length === 0) {
+ try {
+ if (contact.id) {
+ ContactAPI.editContact({
+ id: contact.id,
+ ...formData
+ });
+ } else {
+ ContactAPI.addContact({
+ id: Math.round(Math.random() * 100000000),
+ ...formData
+ });
+ }
+ router.push("/contacts");
+ } catch (error) {
+ console.error('Failed to save contact:', error);
+ setErrors({ submit: error.message });
+ }
+ }
+ };
+
+ return (
+
+ );
+}
+
+ContactForm.propTypes = {
+ contact: PropTypes.shape({
+ id: PropTypes.number,
+ name: PropTypes.string,
+ email: PropTypes.string,
+ phone_number: PropTypes.string,
+ image_url: PropTypes.string,
+ }),
+};
+
+export default ContactForm;
diff --git a/app/components/EditButtons.js b/app/components/EditButtons.js
new file mode 100644
index 0000000..d5287a1
--- /dev/null
+++ b/app/components/EditButtons.js
@@ -0,0 +1,83 @@
+"use client";
+import PropTypes from "prop-types";
+import { useState } from "react";
+import { RiEditLine, RiDeleteBinLine, RiCloseLine } from "react-icons/ri";
+import { useRouter } from "next/navigation";
+
+function EditButtons({ contact, onDelete }) {
+ const [showConfirmation, setShowConfirmation] = useState(false);
+ const [deleteInProgress, setDeleteInProgress] = useState(false);
+ const router = useRouter();
+
+ const handleEdit = () => {
+ if (typeof contact.id === 'number') {
+ router.push(`/contacts/${contact.id}/edit`);
+ } else {
+ console.error('Invalid contact ID:', contact.id);
+ }
+ };
+
+ const handleDelete = async () => {
+ try {
+ setDeleteInProgress(true);
+ await onDelete(contact);
+ setShowConfirmation(false);
+ router.refresh();
+ } catch (error) {
+ console.error('Failed to delete contact:', error);
+ } finally {
+ setDeleteInProgress(false);
+ }
+ };
+
+ return (
+
+
+
+ {!showConfirmation ? (
+
+ ) : (
+
+
+ Delete {contact.name}?
+
+
+
+
+ )}
+
+ );
+}
+
+EditButtons.propTypes = {
+ contact: PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ name: PropTypes.string.isRequired,
+ }).isRequired,
+ onDelete: PropTypes.func.isRequired,
+};
+
+export default EditButtons;
\ No newline at end of file
diff --git a/app/components/Search.js b/app/components/Search.js
new file mode 100644
index 0000000..86c4f19
--- /dev/null
+++ b/app/components/Search.js
@@ -0,0 +1,47 @@
+"use client";
+import { useState } from "react";
+import { RiSearchLine } from "react-icons/ri";
+import PropTypes from "prop-types";
+
+function Search({ onSearchTermChange, initialValue = "" }) {
+ const [term, setTerm] = useState(initialValue);
+
+ const handleClear = () => {
+ setTerm("");
+ onSearchTermChange("");
+ };
+
+ return (
+
+
+
+
+ {
+ setTerm(e.target.value);
+ onSearchTermChange(e.target.value);
+ }}
+ />
+ {term && (
+
+ )}
+
+ );
+}
+
+Search.propTypes = {
+ onSearchTermChange: PropTypes.func.isRequired,
+ initialValue: PropTypes.string,
+};
+
+export default Search;
diff --git a/app/contacts/[id]/edit/page.js b/app/contacts/[id]/edit/page.js
new file mode 100644
index 0000000..2564410
--- /dev/null
+++ b/app/contacts/[id]/edit/page.js
@@ -0,0 +1,39 @@
+"use client";
+import ContactForm from "@/app/components/ContactForm";
+import Link from "next/link";
+import { ContactAPI } from "@/app/data/contactAPI";
+import { ErrorState } from "@/app/components/Contact";
+
+function EditContact({ params }) {
+ const id = Number(params.id);
+
+ // Handle invalid ID
+ if (isNaN(id)) {
+ return ;
+ }
+
+ const contact = ContactAPI.get(id);
+
+ // Handle contact not found
+ if (!contact) {
+ return ;
+ }
+
+ return (
+
+
Edit Contact
+
+
+ Back to Contacts
+
+
+ );
+}
+
+export default EditContact;
diff --git a/app/contacts/[id]/page.js b/app/contacts/[id]/page.js
new file mode 100644
index 0000000..87782e1
--- /dev/null
+++ b/app/contacts/[id]/page.js
@@ -0,0 +1,63 @@
+"use client";
+import Link from "next/link";
+import { useRouter } from "next/navigation";
+import Image from "next/image";
+import EditButtons from "@/app/components/EditButtons";
+import { ContactAPI } from "@/app/data/contactAPI";
+import { ErrorState } from "@/app/components/Contact";
+
+function ContactPage({ params }) {
+ const router = useRouter();
+ const id = Number(params.id);
+
+ // Handle invalid ID
+ if (isNaN(id)) {
+ return ;
+ }
+
+ const contact = ContactAPI.get(id);
+
+ // Handle contact not found
+ if (!contact) {
+ return ;
+ }
+
+ const handleDelete = () => {
+ ContactAPI.remove(contact);
+ router.push("/contacts");
+ };
+
+ return (
+
+
+
{contact.name}
+
{
+ e.target.src = "https://cdn-icons-png.flaticon.com/512/8847/8847419.png";
+ }}
+ />
+
+
Email: {contact.email}
+
Phone: {contact.phone_number}
+
+
+
+ Back to Contacts
+
+
+
+ );
+}
+
+export default ContactPage;
diff --git a/app/contacts/new/page.js b/app/contacts/new/page.js
new file mode 100644
index 0000000..b77ba3f
--- /dev/null
+++ b/app/contacts/new/page.js
@@ -0,0 +1,16 @@
+"use client";
+import Link from "next/link";
+import ContactForm from "../../components/ContactForm";
+import { ContactAPI } from "@/app/data/contactAPI";
+
+function NewContact() {
+ return (
+
+
Add Contact
+
+ Home
+
+ );
+}
+
+export default NewContact;
diff --git a/app/contacts/page.js b/app/contacts/page.js
new file mode 100644
index 0000000..c8ab946
--- /dev/null
+++ b/app/contacts/page.js
@@ -0,0 +1,75 @@
+"use client";
+import Link from "next/link";
+import Contact from "../components/Contact";
+import { ContactAPI } from "../data/contactAPI";
+import { useState } from "react";
+import Search from "../components/Search";
+
+function ContactsPage() {
+ const [contacts, setContacts] = useState(ContactAPI.contacts);
+ const [searchTerm, setSearchTerm] = useState("");
+
+ const handleSearch = (term) => {
+ setSearchTerm(term);
+ const filtered = ContactAPI.contacts.filter((contact) =>
+ contact.name.toLowerCase().includes(term.toLowerCase())
+ );
+ setContacts(filtered);
+ };
+
+ const handleDelete = (contact) => {
+ const updatedContacts = ContactAPI.remove(contact);
+ setContacts(updatedContacts);
+ };
+
+ return (
+
+
+
Contacts
+
+ Add New Contact
+
+
+
+
+
+
+ {contacts.length} contact{contacts.length !== 1 ? 's' : ''} found
+ {searchTerm && ` for "${searchTerm}"`}
+
+
+
+ {contacts.length > 0 ? (
+
+
+
Profile
+
Name
+
Email
+
Phone
+
+
+
+ {contacts.map(contact => (
+ -
+
+
+ ))}
+
+
+ ) : (
+
+
+ {searchTerm
+ ? "No contacts found matching your search."
+ : "No contacts yet. Add your first contact!"}
+
+
+ )}
+
+ );
+}
+
+export default ContactsPage;
diff --git a/app/data/contactAPI.js b/app/data/contactAPI.js
new file mode 100644
index 0000000..d07db2e
--- /dev/null
+++ b/app/data/contactAPI.js
@@ -0,0 +1,86 @@
+const DEFAULT_PROFILE_IMAGE = 'https://cdn-icons-png.flaticon.com/512/8847/8847419.png';
+
+const ContactAPI = {
+ contacts: [],
+
+ all() {
+ return [...this.contacts];
+ },
+
+ get(id) {
+ if (typeof id !== 'number') {
+ throw new Error('ID must be a number');
+ }
+ return this.contacts.find(contact => contact.id === id);
+ },
+
+ addContact({ id, name, email, phone_number, image_url }) {
+ if (!id || !name || !email) {
+ throw new Error('ID, name, and email are required');
+ }
+
+ if (this.contacts.some(contact => contact.id === id)) {
+ throw new Error('Contact with this ID already exists');
+ }
+
+ const newContact = {
+ id,
+ name,
+ email,
+ phone_number: phone_number || '',
+ image_url: image_url || DEFAULT_PROFILE_IMAGE
+ };
+
+ this.contacts.push(newContact);
+ return newContact;
+ },
+
+ remove(contact) {
+ if (!contact || !contact.id) {
+ throw new Error('Valid contact with ID is required');
+ }
+
+ const index = this.contacts.findIndex(c => c.id === contact.id);
+ if (index === -1) {
+ throw new Error('Contact not found');
+ }
+
+ this.contacts.splice(index, 1);
+ return [...this.contacts];
+ },
+
+ editContact({ id, name, email, phone_number, image_url }) {
+ if (!id || !name || !email) {
+ throw new Error('ID, name, and email are required');
+ }
+
+ const index = this.contacts.findIndex(c => c.id === id);
+ if (index === -1) {
+ throw new Error('Contact not found');
+ }
+
+ const updatedContact = {
+ ...this.contacts[index],
+ name,
+ email,
+ phone_number: phone_number || this.contacts[index].phone_number,
+ image_url: image_url || this.contacts[index].image_url || DEFAULT_PROFILE_IMAGE
+ };
+
+ this.contacts[index] = updatedContact;
+ return updatedContact;
+ },
+
+ search(query) {
+ if (!query) return [...this.contacts];
+
+ const searchTerm = query.toLowerCase();
+ return this.contacts.filter(contact =>
+ contact.name.toLowerCase().includes(searchTerm) ||
+ contact.email.toLowerCase().includes(searchTerm) ||
+ contact.phone_number?.toLowerCase().includes(searchTerm)
+ );
+ }
+};
+
+export { ContactAPI };
diff --git a/app/globals.css b/app/globals.css
index d4f491e..a1fa68f 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -1,76 +1,20 @@
:root {
--max-width: 1100px;
- --border-radius: 12px;
- --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono',
- 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
- 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;
-
- --foreground-rgb: 0, 0, 0;
- --background-start-rgb: 214, 219, 220;
- --background-end-rgb: 255, 255, 255;
-
- --primary-glow: conic-gradient(
- from 180deg at 50% 50%,
- #16abff33 0deg,
- #0885ff33 55deg,
- #54d6ff33 120deg,
- #0071ff33 160deg,
- transparent 360deg
- );
- --secondary-glow: radial-gradient(
- rgba(255, 255, 255, 1),
- rgba(255, 255, 255, 0)
- );
-
- --tile-start-rgb: 239, 245, 249;
- --tile-end-rgb: 228, 232, 233;
- --tile-border: conic-gradient(
- #00000080,
- #00000040,
- #00000030,
- #00000020,
- #00000010,
- #00000010,
- #00000080
- );
-
- --callout-rgb: 238, 240, 241;
- --callout-border-rgb: 172, 175, 176;
- --card-rgb: 180, 185, 188;
- --card-border-rgb: 131, 134, 135;
-}
+ --border-radius: 8px;
+ --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
-@media (prefers-color-scheme: dark) {
- :root {
- --foreground-rgb: 255, 255, 255;
- --background-start-rgb: 0, 0, 0;
- --background-end-rgb: 0, 0, 0;
-
- --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
- --secondary-glow: linear-gradient(
- to bottom right,
- rgba(1, 65, 255, 0),
- rgba(1, 65, 255, 0),
- rgba(1, 65, 255, 0.3)
- );
-
- --tile-start-rgb: 2, 13, 46;
- --tile-end-rgb: 2, 5, 19;
- --tile-border: conic-gradient(
- #ffffff80,
- #ffffff40,
- #ffffff30,
- #ffffff20,
- #ffffff10,
- #ffffff10,
- #ffffff80
- );
-
- --callout-rgb: 20, 20, 20;
- --callout-border-rgb: 108, 108, 108;
- --card-rgb: 100, 100, 100;
- --card-border-rgb: 200, 200, 200;
- }
+ /* Modern color palette */
+ --primary-color: #2563eb;
+ --primary-hover: #1d4ed8;
+ --primary-dark: #1a1d23;
+ --secondary-color: #64748b;
+ --background-color: #f8fafc;
+ --surface-color: #ffffff;
+ --text-primary: #1e293b;
+ --text-secondary: #64748b;
+ --error-color: #ef4444;
+ --success-color: #22c55e;
+ --border-color: #e2e8f0;
}
* {
@@ -83,25 +27,414 @@ html,
body {
max-width: 100vw;
overflow-x: hidden;
+ font-family: var(--font-sans);
+ background-color: var(--background-color);
+ color: var(--text-primary);
}
-body {
- color: rgb(var(--foreground-rgb));
- background: linear-gradient(
- to bottom,
- transparent,
- rgb(var(--background-end-rgb))
- )
- rgb(var(--background-start-rgb));
+a {
+ color: var(--primary-color);
+ text-decoration: none;
+ transition: color 0.2s ease;
}
-a {
- color: inherit;
+a:hover {
+ color: var(--primary-hover);
+}
+
+/* Contacts List Styling */
+.contacts-list {
+ background: var(--surface-color);
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.list-header {
+ display: grid;
+ grid-template-columns: 80px 2fr 2fr 1fr 100px;
+ gap: 1rem;
+ padding: 1rem;
+ background: var(--background-alt);
+ border-bottom: 1px solid var(--border-color);
+}
+
+.list-header div {
+ font-weight: 500;
+ color: var(--text-secondary);
+ font-size: 0.9rem;
+}
+
+.contact-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.contact-list li {
+ border-bottom: 1px solid var(--border-color);
+}
+
+.contact-list li:last-child {
+ border-bottom: none;
+}
+
+.contact-list li:hover {
+ background: var(--hover-color);
+}
+
+.contact-list a {
+ color: var(--primary-color);
+ font-weight: 500;
+ text-decoration: none;
+ transition: color 0.2s;
+}
+
+.contact-list a:hover {
+ color: var(--primary-dark);
+ text-decoration: underline;
+}
+
+.contact-list .contact-name {
+ font-size: 1rem;
+ line-height: 1.4;
+}
+
+/* Contact Item Styling */
+.contact-item {
+ display: grid;
+ grid-template-columns: 80px 2fr 2fr 1fr 100px;
+ gap: 1rem;
+ align-items: center;
+ padding: 1rem;
+ transition: background-color 0.2s;
+ border-bottom: 1px solid var(--border-color);
+}
+
+.contact-item:last-child {
+ border-bottom: none;
+}
+
+.contact-item:hover {
+ background-color: var(--hover-color);
+}
+
+.contact-profile {
+ display: flex;
+ align-items: center;
+}
+
+.profile-image {
+ border-radius: 50%;
+ object-fit: cover;
+ background-color: var(--background-alt);
+}
+
+.contact-name {
+ font-weight: 500;
+}
+
+.name-link {
+ color: var(--primary-color);
+ text-decoration: none;
+ transition: color 0.2s;
+}
+
+.name-link:hover {
+ color: var(--primary-dark);
+ text-decoration: underline;
+}
+
+.contact-email {
+ color: var(--text-secondary);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.contact-phone {
+ color: var(--text-secondary);
+ font-size: 0.9rem;
+}
+
+.contact-actions {
+ display: flex;
+ gap: 0.5rem;
+ justify-content: flex-end;
+}
+
+/* Responsive adjustments */
+@media (max-width: 768px) {
+ .contact-item {
+ grid-template-columns: 60px 1fr auto;
+ gap: 0.75rem;
+ }
+
+ .contact-email,
+ .contact-phone {
+ display: none;
+ }
+}
+
+/* Search Section */
+.search-section {
+ margin-bottom: 1.5rem;
+}
+
+.results-count {
+ margin-top: 0.5rem;
+ color: var(--text-secondary);
+ font-size: 0.9rem;
+}
+
+/* Empty State */
+.empty-state {
+ text-align: center;
+ padding: 3rem 1rem;
+ background: var(--surface-color);
+ border-radius: 8px;
+ color: var(--text-secondary);
+}
+
+/* Header Section */
+.header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 2rem;
+}
+
+.primary-button {
+ background: var(--primary-color);
+ color: white;
+ padding: 0.5rem 1rem;
+ border-radius: 6px;
text-decoration: none;
+ font-weight: 500;
+ transition: background 0.2s;
+}
+
+.primary-button:hover {
+ background: var(--primary-dark);
+}
+
+/* Form Styling */
+form {
+ max-width: 600px;
+ margin: 2rem auto;
+ padding: 2rem;
+ background-color: var(--surface-color);
+ border-radius: var(--border-radius);
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+}
+
+input, textarea {
+ width: 100%;
+ padding: 0.75rem;
+ margin: 0.5rem 0 1rem;
+ border: 1px solid var(--border-color);
+ border-radius: var(--border-radius);
+ font-size: 1rem;
+ transition: border-color 0.2s ease;
+}
+
+input:focus, textarea:focus {
+ outline: none;
+ border-color: var(--primary-color);
+}
+
+/* Button Styling */
+button {
+ padding: 0.5rem 1rem;
+ border: none;
+ border-radius: var(--border-radius);
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+.secondary-button {
+ background-color: var(--secondary-color);
+ color: white;
+}
+
+.secondary-button:hover {
+ background-color: #4b5563;
+}
+
+.delete-button {
+ background-color: var(--error-color);
+ color: white;
+}
+
+.delete-button:hover {
+ background-color: #dc2626;
+}
+
+.cancel-button {
+ padding: 0.5rem;
+ border: none;
+ background: none;
+ cursor: pointer;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: background-color 0.2s;
+}
+
+.cancel-button:hover {
+ background-color: rgba(220, 38, 38, 0.1);
+}
+
+.cancel-button:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+/* Error Messages */
+.error-message {
+ color: var(--error-color);
+ font-size: 0.875rem;
+ margin-top: -0.5rem;
+ margin-bottom: 1rem;
+}
+
+/* Container */
+.container {
+ max-width: var(--max-width);
+ margin: 0 auto;
+ padding: 2rem;
+}
+
+/* Page Header */
+.page-header {
+ margin-bottom: 2rem;
+ padding-bottom: 1rem;
+ border-bottom: 1px solid var(--border-color);
+}
+
+.page-header h1 {
+ color: var(--text-primary);
+ font-size: 2rem;
+ font-weight: 600;
+}
+
+/* Search Bar Styling */
+.search-container {
+ margin: 1rem 0;
+ width: 100%;
+}
+
+.search-input-wrapper {
+ position: relative;
+ display: flex;
+ align-items: center;
+ background-color: var(--surface-color);
+ border: 1px solid var(--border-color);
+ border-radius: var(--border-radius);
+ padding: 0.5rem;
+ transition: all 0.2s ease;
+}
+
+.search-input-wrapper:focus-within {
+ border-color: var(--primary-color);
+ box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
+}
+
+.search-icon {
+ color: var(--text-secondary);
+ margin-right: 0.5rem;
+}
+
+.search-input {
+ flex: 1;
+ border: none;
+ background: none;
+ padding: 0.5rem;
+ font-size: 1rem;
+ color: var(--text-primary);
+ width: 100%;
+}
+
+.search-input::placeholder {
+ color: var(--text-secondary);
+}
+
+.search-input:focus {
+ outline: none;
+}
+
+.clear-button {
+ background: none;
+ border: none;
+ padding: 0.25rem;
+ color: var(--text-secondary);
+ cursor: pointer;
+ border-radius: var(--border-radius);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.2s ease;
+}
+
+.clear-button:hover {
+ background-color: var(--border-color);
+ color: var(--text-primary);
}
+/* Circle Image Styling */
+.circle {
+ border-radius: 50%;
+ object-fit: cover;
+ border: 2px solid var(--border-color);
+ transition: border-color 0.2s ease;
+}
+
+.circle:hover {
+ border-color: var(--primary-color);
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .contact-grid {
+ grid-template-columns: auto 1fr;
+ gap: 1rem;
+ padding: 1rem;
+ }
+
+ .contact-grid li:not(:first-child):not(:nth-child(2)) {
+ grid-column: 1 / -1;
+ padding-left: calc(50px + 1rem);
+ }
+
+ .contact-grid li:last-child {
+ justify-self: start;
+ }
+}
+
+@media (max-width: 768px) {
+ .contact-grid {
+ display: block;
+ }
+
+ .grid-headers {
+ display: none;
+ }
+}
+
+/* Dark Mode */
@media (prefers-color-scheme: dark) {
- html {
- color-scheme: dark;
+ :root {
+ --background-color: #1a1d23;
+ --surface-color: #2f343a;
+ --text-primary: #ffffff;
+ --text-secondary: #a1a1aa;
+ --primary-color: #4f46e5;
+ --primary-hover: #4338ca;
+ --secondary-color: #6b7280;
+ --error-color: #ef4444;
+ --success-color: #22c55e;
+ --border-color: #4b5563;
}
}
diff --git a/app/page.js b/app/page.js
index 5f905a8..0f36a5e 100644
--- a/app/page.js
+++ b/app/page.js
@@ -1,95 +1,12 @@
-import Image from 'next/image'
-import styles from './page.module.css'
+import ContactPage from "./contacts/page";
-export default function Home() {
+function Home() {
return (
-
-
-
- Get started by editing
- app/page.js
-
-
-
-
-
-
-
-
-
+
+ Welcome to Your Contact List
+
- )
+ );
}
+
+export default Home;
diff --git a/package-lock.json b/package-lock.json
index f3ada0d..5c611ad 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,14 +7,18 @@
"": {
"name": "parsity_contact_list_eval",
"version": "0.1.0",
+ "license": "ISC",
"dependencies": {
- "next": "14.0.2",
+ "next": "^14.2.28",
+ "proptypes": "^1.1.0",
"react": "^18",
- "react-dom": "^18"
+ "react-dom": "^18",
+ "react-icons": "^5.3.0"
},
"devDependencies": {
"eslint": "^8",
- "eslint-config-next": "14.0.2"
+ "eslint-config-next": "14.0.2",
+ "jsdoc": "^4.0.3"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -26,11 +30,48 @@
"node": ">=0.10.0"
}
},
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
+ "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+ "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz",
+ "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.27.0"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/@babel/runtime": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz",
- "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==",
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
+ "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -38,6 +79,20 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/types": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz",
+ "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.25.9",
+ "@babel/helper-validator-identifier": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@@ -127,10 +182,24 @@
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
"dev": true
},
+ "node_modules/@jsdoc/salty": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz",
+ "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "lodash": "^4.17.21"
+ },
+ "engines": {
+ "node": ">=v12.0.0"
+ }
+ },
"node_modules/@next/env": {
- "version": "14.0.2",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.2.tgz",
- "integrity": "sha512-HAW1sljizEaduEOes/m84oUqeIDAUYBR1CDwu2tobNlNDFP3cSm9d6QsOsGeNlIppU1p/p1+bWbYCbvwjFiceA=="
+ "version": "14.2.28",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.28.tgz",
+ "integrity": "sha512-PAmWhJfJQlP+kxZwCjrVd9QnR5x0R3u0mTXTiZDgSd4h5LdXmjxCCWbN9kq6hkZBOax8Rm3xDW5HagWyJuT37g==",
+ "license": "MIT"
},
"node_modules/@next/eslint-plugin-next": {
"version": "14.0.2",
@@ -142,12 +211,13 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
- "version": "14.0.2",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.2.tgz",
- "integrity": "sha512-i+jQY0fOb8L5gvGvojWyZMfQoQtDVB2kYe7fufOEiST6sicvzI2W5/EXo4lX5bLUjapHKe+nFxuVv7BA+Pd7LQ==",
+ "version": "14.2.28",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.28.tgz",
+ "integrity": "sha512-kzGChl9setxYWpk3H6fTZXXPFFjg7urptLq5o5ZgYezCrqlemKttwMT5iFyx/p1e/JeglTwDFRtb923gTJ3R1w==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -157,12 +227,13 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "14.0.2",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.2.tgz",
- "integrity": "sha512-zRCAO0d2hW6gBEa4wJaLn+gY8qtIqD3gYd9NjruuN98OCI6YyelmhWVVLlREjS7RYrm9OUQIp/iVJFeB6kP1hg==",
+ "version": "14.2.28",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.28.tgz",
+ "integrity": "sha512-z6FXYHDJlFOzVEOiiJ/4NG8aLCeayZdcRSMjPDysW297Up6r22xw6Ea9AOwQqbNsth8JNgIK8EkWz2IDwaLQcw==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -172,12 +243,13 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "14.0.2",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.2.tgz",
- "integrity": "sha512-tSJmiaon8YaKsVhi7GgRizZoV0N1Sx5+i+hFTrCKKQN7s3tuqW0Rov+RYdPhAv/pJl4qiG+XfSX4eJXqpNg3dA==",
+ "version": "14.2.28",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.28.tgz",
+ "integrity": "sha512-9ARHLEQXhAilNJ7rgQX8xs9aH3yJSj888ssSjJLeldiZKR4D7N08MfMqljk77fAwZsWwsrp8ohHsMvurvv9liQ==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -187,12 +259,13 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "14.0.2",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.2.tgz",
- "integrity": "sha512-dXJLMSEOwqJKcag1BeX1C+ekdPPJ9yXbWIt3nAadhbLx5CjACoB2NQj9Xcqu2tmdr5L6m34fR+fjGPs+ZVPLzA==",
+ "version": "14.2.28",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.28.tgz",
+ "integrity": "sha512-p6gvatI1nX41KCizEe6JkF0FS/cEEF0u23vKDpl+WhPe/fCTBeGkEBh7iW2cUM0rvquPVwPWdiUR6Ebr/kQWxQ==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -202,12 +275,13 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "14.0.2",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.2.tgz",
- "integrity": "sha512-WC9KAPSowj6as76P3vf1J3mf2QTm3Wv3FBzQi7UJ+dxWjK3MhHVWsWUo24AnmHx9qDcEtHM58okgZkXVqeLB+Q==",
+ "version": "14.2.28",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.28.tgz",
+ "integrity": "sha512-nsiSnz2wO6GwMAX2o0iucONlVL7dNgKUqt/mDTATGO2NY59EO/ZKnKEr80BJFhuA5UC1KZOMblJHWZoqIJddpA==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -217,12 +291,13 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "14.0.2",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.2.tgz",
- "integrity": "sha512-KSSAwvUcjtdZY4zJFa2f5VNJIwuEVnOSlqYqbQIawREJA+gUI6egeiRu290pXioQXnQHYYdXmnVNZ4M+VMB7KQ==",
+ "version": "14.2.28",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.28.tgz",
+ "integrity": "sha512-+IuGQKoI3abrXFqx7GtlvNOpeExUH1mTIqCrh1LGFf8DnlUcTmOOCApEnPJUSLrSbzOdsF2ho2KhnQoO0I1RDw==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -232,12 +307,13 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "14.0.2",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.2.tgz",
- "integrity": "sha512-2/O0F1SqJ0bD3zqNuYge0ok7OEWCQwk55RPheDYD0va5ij7kYwrFkq5ycCRN0TLjLfxSF6xI5NM6nC5ux7svEQ==",
+ "version": "14.2.28",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.28.tgz",
+ "integrity": "sha512-l61WZ3nevt4BAnGksUVFKy2uJP5DPz2E0Ma/Oklvo3sGj9sw3q7vBWONFRgz+ICiHpW5mV+mBrkB3XEubMrKaA==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -247,12 +323,13 @@
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
- "version": "14.0.2",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.2.tgz",
- "integrity": "sha512-vJI/x70Id0oN4Bq/R6byBqV1/NS5Dl31zC+lowO8SDu1fHmUxoAdILZR5X/sKbiJpuvKcCrwbYgJU8FF/Gh50Q==",
+ "version": "14.2.28",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.28.tgz",
+ "integrity": "sha512-+Kcp1T3jHZnJ9v9VTJ/yf1t/xmtFAc/Sge4v7mVc1z+NYfYzisi8kJ9AsY8itbgq+WgEwMtOpiLLJsUy2qnXZw==",
"cpu": [
"ia32"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -262,12 +339,13 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "14.0.2",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.2.tgz",
- "integrity": "sha512-Ut4LXIUvC5m8pHTe2j0vq/YDnTEyq6RSR9vHYPqnELrDapPhLNz9Od/L5Ow3J8RNDWpEnfCiQXuVdfjlNEJ7ug==",
+ "version": "14.2.28",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.28.tgz",
+ "integrity": "sha512-1gCmpvyhz7DkB1srRItJTnmR2UwQPAUXXIg9r0/56g3O8etGmwlX68skKXJOp9EejW3hhv7nSQUJ2raFiz4MoA==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -317,11 +395,19 @@
"integrity": "sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==",
"dev": true
},
+ "node_modules/@swc/counter": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
+ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
+ "license": "Apache-2.0"
+ },
"node_modules/@swc/helpers": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
- "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==",
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz",
+ "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==",
+ "license": "Apache-2.0",
"dependencies": {
+ "@swc/counter": "^0.1.3",
"tslib": "^2.4.0"
}
},
@@ -331,6 +417,31 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true
},
+ "node_modules/@types/linkify-it": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/markdown-it": {
+ "version": "14.1.2",
+ "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
+ "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/linkify-it": "^5",
+ "@types/mdurl": "^2"
+ }
+ },
+ "node_modules/@types/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@typescript-eslint/parser": {
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.10.0.tgz",
@@ -696,6 +807,13 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
+ "node_modules/bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -707,12 +825,13 @@
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -753,9 +872,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001561",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz",
- "integrity": "sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==",
+ "version": "1.0.30001714",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001714.tgz",
+ "integrity": "sha512-mtgapdwDLSSBnCI3JokHM7oEQBLxiJKVRtg10AxM1AyeiKcM96f0Mkbqeq+1AbiCtvMcHRulAAEMu693JrSWqg==",
"funding": [
{
"type": "opencollective",
@@ -769,7 +888,21 @@
"type": "github",
"url": "https://github.com/sponsors/ai"
}
- ]
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/catharsis": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
+ "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lodash": "^4.17.15"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
},
"node_modules/chalk": {
"version": "4.1.2",
@@ -817,10 +950,11 @@
"dev": true
},
"node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -942,6 +1076,19 @@
"node": ">=10.13.0"
}
},
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/es-abstract": {
"version": "1.22.3",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz",
@@ -1547,10 +1694,11 @@
}
},
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -1720,11 +1868,6 @@
"node": ">=10.13.0"
}
},
- "node_modules/glob-to-regexp": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
- "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
- },
"node_modules/globals": {
"version": "13.23.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
@@ -2113,6 +2256,7 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.12.0"
}
@@ -2299,6 +2443,56 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/js2xmlparser": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
+ "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "xmlcreate": "^2.0.4"
+ }
+ },
+ "node_modules/jsdoc": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz",
+ "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@babel/parser": "^7.20.15",
+ "@jsdoc/salty": "^0.2.1",
+ "@types/markdown-it": "^14.1.1",
+ "bluebird": "^3.7.2",
+ "catharsis": "^0.9.0",
+ "escape-string-regexp": "^2.0.0",
+ "js2xmlparser": "^4.0.2",
+ "klaw": "^3.0.0",
+ "markdown-it": "^14.1.0",
+ "markdown-it-anchor": "^8.6.7",
+ "marked": "^4.0.10",
+ "mkdirp": "^1.0.4",
+ "requizzle": "^0.2.3",
+ "strip-json-comments": "^3.1.0",
+ "underscore": "~1.13.2"
+ },
+ "bin": {
+ "jsdoc": "jsdoc.js"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/jsdoc/node_modules/escape-string-regexp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@@ -2353,6 +2547,16 @@
"json-buffer": "3.0.1"
}
},
+ "node_modules/klaw": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
+ "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.1.9"
+ }
+ },
"node_modules/language-subtag-registry": {
"version": "0.3.22",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
@@ -2384,6 +2588,16 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/linkify-it": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "uc.micro": "^2.0.0"
+ }
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -2399,6 +2613,13 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -2428,6 +2649,55 @@
"node": ">=10"
}
},
+ "node_modules/markdown-it": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
+ "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1",
+ "entities": "^4.4.0",
+ "linkify-it": "^5.0.0",
+ "mdurl": "^2.0.0",
+ "punycode.js": "^2.3.1",
+ "uc.micro": "^2.1.0"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.mjs"
+ }
+ },
+ "node_modules/markdown-it-anchor": {
+ "version": "8.6.7",
+ "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz",
+ "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==",
+ "dev": true,
+ "license": "Unlicense",
+ "peerDependencies": {
+ "@types/markdown-it": "*",
+ "markdown-it": "*"
+ }
+ },
+ "node_modules/marked": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
+ "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -2438,12 +2708,13 @@
}
},
"node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -2471,6 +2742,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -2478,15 +2762,16 @@
"dev": true
},
"node_modules/nanoid": {
- "version": "3.3.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -2501,17 +2786,18 @@
"dev": true
},
"node_modules/next": {
- "version": "14.0.2",
- "resolved": "https://registry.npmjs.org/next/-/next-14.0.2.tgz",
- "integrity": "sha512-jsAU2CkYS40GaQYOiLl9m93RTv2DA/tTJ0NRlmZIBIL87YwQ/xR8k796z7IqgM3jydI8G25dXvyYMC9VDIevIg==",
+ "version": "14.2.28",
+ "resolved": "https://registry.npmjs.org/next/-/next-14.2.28.tgz",
+ "integrity": "sha512-QLEIP/kYXynIxtcKB6vNjtWLVs3Y4Sb+EClTC/CSVzdLD1gIuItccpu/n1lhmduffI32iPGEK2cLLxxt28qgYA==",
+ "license": "MIT",
"dependencies": {
- "@next/env": "14.0.2",
- "@swc/helpers": "0.5.2",
+ "@next/env": "14.2.28",
+ "@swc/helpers": "0.5.5",
"busboy": "1.6.0",
- "caniuse-lite": "^1.0.30001406",
+ "caniuse-lite": "^1.0.30001579",
+ "graceful-fs": "^4.2.11",
"postcss": "8.4.31",
- "styled-jsx": "5.1.1",
- "watchpack": "2.4.0"
+ "styled-jsx": "5.1.1"
},
"bin": {
"next": "dist/bin/next"
@@ -2520,18 +2806,19 @@
"node": ">=18.17.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "14.0.2",
- "@next/swc-darwin-x64": "14.0.2",
- "@next/swc-linux-arm64-gnu": "14.0.2",
- "@next/swc-linux-arm64-musl": "14.0.2",
- "@next/swc-linux-x64-gnu": "14.0.2",
- "@next/swc-linux-x64-musl": "14.0.2",
- "@next/swc-win32-arm64-msvc": "14.0.2",
- "@next/swc-win32-ia32-msvc": "14.0.2",
- "@next/swc-win32-x64-msvc": "14.0.2"
+ "@next/swc-darwin-arm64": "14.2.28",
+ "@next/swc-darwin-x64": "14.2.28",
+ "@next/swc-linux-arm64-gnu": "14.2.28",
+ "@next/swc-linux-arm64-musl": "14.2.28",
+ "@next/swc-linux-x64-gnu": "14.2.28",
+ "@next/swc-linux-x64-musl": "14.2.28",
+ "@next/swc-win32-arm64-msvc": "14.2.28",
+ "@next/swc-win32-ia32-msvc": "14.2.28",
+ "@next/swc-win32-x64-msvc": "14.2.28"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
+ "@playwright/test": "^1.41.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sass": "^1.3.0"
@@ -2540,6 +2827,9 @@
"@opentelemetry/api": {
"optional": true
},
+ "@playwright/test": {
+ "optional": true
+ },
"sass": {
"optional": true
}
@@ -2837,6 +3127,12 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/proptypes": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proptypes/-/proptypes-1.1.0.tgz",
+ "integrity": "sha512-589N0gHNvg6ocCDia1knxMwguEcZq1qyD8fVxFZEdZP0YKI+GTHyflsJH2mYE0YZbo1KNj5W8avdSR4iJDV+fw==",
+ "license": "BSD"
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -2846,6 +3142,16 @@
"node": ">=6"
}
},
+ "node_modules/punycode.js": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+ "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -2889,6 +3195,15 @@
"react": "^18.2.0"
}
},
+ "node_modules/react-icons": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
+ "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -2938,6 +3253,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/requizzle": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz",
+ "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lodash": "^4.17.21"
+ }
+ },
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@@ -3329,6 +3654,7 @@
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
@@ -3361,9 +3687,10 @@
}
},
"node_modules/tslib": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
},
"node_modules/type-check": {
"version": "0.4.0",
@@ -3468,6 +3795,13 @@
"node": ">=14.17"
}
},
+ "node_modules/uc.micro": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
@@ -3483,6 +3817,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/underscore": {
+ "version": "1.13.7",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
+ "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -3492,18 +3833,6 @@
"punycode": "^2.1.0"
}
},
- "node_modules/watchpack": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
- "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
- "dependencies": {
- "glob-to-regexp": "^0.4.1",
- "graceful-fs": "^4.1.2"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -3601,6 +3930,13 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
+ "node_modules/xmlcreate": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
+ "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
diff --git a/package.json b/package.json
index 5f7406f..4ad47ca 100644
--- a/package.json
+++ b/package.json
@@ -9,12 +9,20 @@
"lint": "next lint"
},
"dependencies": {
+ "next": "^14.2.28",
+ "proptypes": "^1.1.0",
"react": "^18",
"react-dom": "^18",
- "next": "14.0.2"
+ "react-icons": "^5.3.0"
},
"devDependencies": {
"eslint": "^8",
- "eslint-config-next": "14.0.2"
- }
+ "eslint-config-next": "14.0.2",
+ "jsdoc": "^4.0.3"
+ },
+ "description": "This project has been created by a student at Parsity, an online software engineering course. The work in this repository is wholly of the student based on a sample starter project that can be accessed by looking at the repository that this project forks.",
+ "main": "next.config.js",
+ "keywords": [],
+ "author": "",
+ "license": "ISC"
}