diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..3e43185 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,53 @@ +body { + font-family: 'Heebo', sans-serif; + background-color: #F8FAFC; +} + +.navbar-brand { + font-weight: 700; + font-size: 1.5rem; +} + +.btn-primary { + background-color: #1D4ED8; + border-color: #1D4ED8; +} +.btn-primary:hover { + background-color: #1E40AF; + border-color: #1E40AF; +} + +.btn-secondary { + background-color: #F97316; + border-color: #F97316; +} +.btn-secondary:hover { + background-color: #EA580C; + border-color: #EA580C; +} + +.card { + border-radius: 0.5rem; + border: 1px solid #e2e8f0; + box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.05), 0 1px 2px -1px rgb(0 0 0 / 0.05); +} + +.form-control, .form-select { + border-radius: 0.5rem; +} +.form-control:focus, .form-select:focus { + border-color: #1D4ED8; + box-shadow: 0 0 0 0.25rem rgba(29, 78, 216, 0.25); +} + +.table { + vertical-align: middle; +} + +.duration-input-group { + direction: ltr; +} + +.toast-container { + z-index: 1080; +} diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..c19d73a --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,81 @@ +document.addEventListener('DOMContentLoaded', function () { + // Initialize toast notifications + const toastEl = document.getElementById('notificationToast'); + if (toastEl) { + const toast = new bootstrap.Toast(toastEl, { delay: 3000 }); + toast.show(); + } + + const songModalEl = document.getElementById('songModal'); + if (!songModalEl) return; + + const songModal = new bootstrap.Modal(songModalEl); + const modalTitle = songModalEl.querySelector('.modal-title'); + const songForm = document.getElementById('songForm'); + const actionInput = document.getElementById('action'); + const songIdInput = document.getElementById('song_id'); + + // Function to reset the modal to its "Add Song" state + const resetModal = () => { + songForm.reset(); + actionInput.value = 'create'; + songIdInput.value = ''; + modalTitle.textContent = 'הוספת שיר חדש'; + }; + + // Handle clicks on edit buttons + document.querySelectorAll('.edit-btn').forEach(button => { + button.addEventListener('click', function () { + const song = JSON.parse(this.dataset.song); + + resetModal(); // Start with a clean slate + + actionInput.value = 'update'; + modalTitle.textContent = 'עריכת שיר'; + songIdInput.value = song.id; + + document.getElementById('name').value = song.name; + document.getElementById('bpm').value = song.bpm; + + if (song.song_key && song.song_key.trim() !== '') { + const keyParts = song.song_key.split(' '); + document.getElementById('key_note').value = keyParts[0]; + document.getElementById('key_scale').value = keyParts[1] || 'Major'; + } else { + document.getElementById('key_note').value = ''; + document.getElementById('key_scale').value = 'Major'; + } + + document.getElementById('notes').value = song.notes; + document.getElementById('tags').value = song.tags; + + if (song.duration_seconds) { + const minutes = Math.floor(song.duration_seconds / 60); + const seconds = song.duration_seconds % 60; + document.getElementById('duration_minutes').value = minutes; + document.getElementById('duration_seconds').value = seconds; + } + + songModal.show(); + }); + }); + + // Handle click on the link to add the first song + const addSongBtnLink = document.getElementById('addSongBtnLink'); + if(addSongBtnLink) { + addSongBtnLink.addEventListener('click', (e) => { + e.preventDefault(); + resetModal(); + songModal.show(); + }); + } + + // Reset the modal form when it's opened via the main "Add Song" button + // The main button works via data-attributes, so we just need to hook into the event + songModalEl.addEventListener('show.bs.modal', function (event) { + // If the trigger was NOT an edit button, reset the form for adding. + if (event.relatedTarget && !event.relatedTarget.classList.contains('edit-btn')) { + resetModal(); + } + }); +}); \ No newline at end of file diff --git a/db/migrate.php b/db/migrate.php new file mode 100644 index 0000000..7065604 --- /dev/null +++ b/db/migrate.php @@ -0,0 +1,38 @@ + PDO::ERRMODE_EXCEPTION, + ]); + $pdo_admin->exec("CREATE DATABASE IF NOT EXISTS `".DB_NAME."` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); + // echo "Database '".DB_NAME."' created or already exists.\n"; + + // 2. Connect to the specific database to create tables + $pdo = db(); + if ($pdo === null) { + throw new Exception("Failed to connect to the database. The db() function returned null."); + } + $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $sql = " + CREATE TABLE IF NOT EXISTS songs ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + bpm INT, + song_key VARCHAR(50), + duration_seconds INT, + notes TEXT, + tags VARCHAR(255), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"; + + $pdo->exec($sql); + // echo "Table 'songs' created successfully (if it didn\'t exist).\n"; + +} catch (Exception $e) { + http_response_code(500); + die("DB ERROR: " . $e->getMessage()); +} \ No newline at end of file diff --git a/includes/footer.php b/includes/footer.php new file mode 100644 index 0000000..85bc74f --- /dev/null +++ b/includes/footer.php @@ -0,0 +1,9 @@ + + + + + +