diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 9a8559d..0d90a6d 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -10,7 +10,8 @@
"dependencies": {
"react": "^19.1.0",
"react-beautiful-dnd": "^13.1.1",
- "react-dom": "^19.1.0"
+ "react-dom": "^19.1.0",
+ "react-icons": "^5.5.0"
},
"devDependencies": {
"@eslint/js": "^9.25.0",
@@ -2393,6 +2394,14 @@
"react": "^19.1.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==",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 9a6dfe2..e2a3347 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -12,7 +12,8 @@
"dependencies": {
"react": "^19.1.0",
"react-beautiful-dnd": "^13.1.1",
- "react-dom": "^19.1.0"
+ "react-dom": "^19.1.0",
+ "react-icons": "^5.5.0"
},
"devDependencies": {
"@eslint/js": "^9.25.0",
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index adc33df..40e526d 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -2,7 +2,7 @@
import { useEffect, useState } from 'react';
import './App.css';
import SectionGrid from './components/SectionGrid';
-import ControlPanel from './components/ControlPanel';
+import AddAppModal from './components/AddAppModal';
function App() {
const [sections, setSections] = useState([]);
@@ -20,7 +20,7 @@ function App() {
return (
🔷 Navix
-
+
window.location.reload()} />
{sections.map((section) => (
))}
diff --git a/frontend/src/components/AddAppModal.jsx b/frontend/src/components/AddAppModal.jsx
new file mode 100644
index 0000000..5826ad3
--- /dev/null
+++ b/frontend/src/components/AddAppModal.jsx
@@ -0,0 +1,66 @@
+import { useState } from 'react';
+import { addAppToSection } from '../services/api';
+import '../style/AddAppModal.css';
+import { IoIosAddCircleOutline } from "react-icons/io";
+
+function AddAppModal({ onAdded }) {
+ const [open, setOpen] = useState(false);
+ const [spin, setSpin] = useState(false);
+
+ const [section, setSection] = useState('');
+ const [name, setName] = useState('');
+ const [icon, setIcon] = useState('');
+ const [description, setDescription] = useState('');
+ const [url, setUrl] = useState('');
+
+ const handleOpen = () => {
+ setSpin(true);
+ setTimeout(() => {
+ setSpin(false);
+ setOpen(true);
+ }, 500); // match spin animation duration
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ try {
+ await addAppToSection({ section, app: { name, icon, description, url } });
+ setOpen(false);
+ setSection('');
+ setName('');
+ setIcon('');
+ setDescription('');
+ setUrl('');
+ if (onAdded) onAdded();
+ } catch (err) {
+ alert('Failed to add app');
+ }
+ };
+
+ return (
+ <>
+
+
+ {open && (
+ setOpen(false)}>
+
e.stopPropagation()}>
+
Add New App
+
+
+
+ )}
+ >
+ );
+}
+
+export default AddAppModal;
diff --git a/frontend/src/components/ControlPanel.jsx b/frontend/src/components/ControlPanel.jsx
deleted file mode 100644
index d8b5b11..0000000
--- a/frontend/src/components/ControlPanel.jsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { useState } from 'react';
-import { addAppToSection } from '../services/api';
-import '../style/ControlPanel.css';
-
-function ControlPanel({ onUpdate }) {
- const [section, setSection] = useState('');
- const [name, setName] = useState('');
- const [icon, setIcon] = useState('');
- const [description, setDescription] = useState('');
- const [url, setUrl] = useState('');
-
- const handleSubmit = async (e) => {
- e.preventDefault();
- if (!section || !name || !url) return;
-
- try {
- await addAppToSection({
- section,
- app: { name, icon, description, url }
- });
-
- if (onUpdate) onUpdate();
- setSection('');
- setName('');
- setIcon('');
- setDescription('');
- setUrl('');
- } catch (err) {
- console.error('Failed to add app:', err);
- }
- };
-
- return (
-
- );
-}
-
-export default ControlPanel;
diff --git a/frontend/src/style/AddAppModal.css b/frontend/src/style/AddAppModal.css
new file mode 100644
index 0000000..067a32e
--- /dev/null
+++ b/frontend/src/style/AddAppModal.css
@@ -0,0 +1,84 @@
+.add-button {
+ position: fixed;
+ bottom: 2rem;
+ right: 2rem;
+ background-color: #007bff;
+ color: white;
+ font-size: 2rem;
+ border-radius: 50%;
+ width: 60px;
+ height: 60px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ z-index: 999;
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
+ transition: background-color 0.3s ease;
+}
+
+.add-button:hover {
+ background-color: #0056b3;
+}
+
+.modal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+}
+
+.modal {
+ background: #1e1e1e;
+ padding: 2rem;
+ border-radius: 12px;
+ width: 340px;
+ height: 420px;
+ box-shadow: 0 0 10px #000;
+
+ /* Flexbox centering */
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+
+.modal input {
+ width: 90%;
+ height: 35px;
+ padding: 0.5rem;
+ margin-bottom: 0.75rem;
+ background-color: #2c2c2c;
+ border: none;
+ color: white;
+ border-radius: 6px;
+}
+
+.modal button {
+ width: 90%;
+ padding: 0.5rem;
+ background-color: #007bff;
+ color: white;
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
+}
+
+.modal button:hover {
+ background-color: #0056b3;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+.add-button.spin {
+ animation: spin 0.5s linear;
+}
diff --git a/frontend/src/style/ControlPanel.css b/frontend/src/style/ControlPanel.css
deleted file mode 100644
index ed27afc..0000000
--- a/frontend/src/style/ControlPanel.css
+++ /dev/null
@@ -1,27 +0,0 @@
-.control-panel {
- display: flex;
- flex-direction: column;
- gap: 0.5rem;
- margin-bottom: 2rem;
- background-color: #1e1e1e;
- padding: 1rem;
- border-radius: 8px;
- max-width: 400px;
-}
-
-.control-panel input,
-.control-panel button {
- padding: 0.5rem;
- border: none;
- border-radius: 4px;
-}
-
-.control-panel button {
- background-color: #007bff;
- color: white;
- cursor: pointer;
-}
-
-.control-panel button:hover {
- background-color: #0056b3;
-}