| @ -1,3 +1,3 @@ | |||
| docker build --no-cache -t creylopez/lyrics:5.4 . | |||
| docker push creylopez/lyrics:5.4 | |||
| docker build --no-cache -t creylopez/lyrics:6.0 . | |||
| docker push creylopez/lyrics:6.0 | |||
| @ -1,78 +0,0 @@ | |||
| <nav class="navbar is-dark" role="navigation" aria-label="main navigation"> | |||
| <div class="navbar-brand"> | |||
| <img src="{{ url_for('static', filename='bruce.jpeg') }}" class="image is-48x48"/> | |||
| <a class="navbar-item" href="/">Letras de canciones</a> | |||
| <div class="navbar-burger" role="button" data-target="navMenu"> | |||
| <span></span> | |||
| {% if current_user.is_authenticated %} | |||
| <span></span> | |||
| <span></span> | |||
| {% else %} | |||
| <span></span> | |||
| <span></span> | |||
| {% endif %} | |||
| </div> | |||
| </div> | |||
| <div class="navbar-menu" id="navMenu"> | |||
| <div class="navbar-end"> | |||
| <a class="navbar-item" href="{{ url_for('paginas.index') }}" > | |||
| Inicio | |||
| </a> | |||
| <div class="navbar-item"> | |||
| <!-- <div class="buttons">--> | |||
| {% if current_user.is_authenticated %} | |||
| <a class="navbar-item" href="{{ url_for('paginas.add_song') }}">Añadir canción</a> | |||
| <a class="navbar-item" href="{{ url_for('paginas.add_album') }}">Añadir álbum</a> | |||
| <div class="navbar-item has-dropdown is-hoverable"> | |||
| <a class="navbar-link"> | |||
| {{ current_user.username }} | |||
| </a> | |||
| <div class="navbar-dropdown"> | |||
| <a href="{{ url_for('paginas.index') }}" class="navbar-item">Perfil</a> | |||
| <a href="{{ url_for('auth.logout') }}" class="navbar-item">Salir</a> | |||
| </div> | |||
| </div> | |||
| {% else %} | |||
| <a href="{{ url_for('auth.login') }}" class="button is-primary">Entrar</a> | |||
| <a href="{{ url_for('auth.signup') }}" class="button is-light">Registrarse</a> | |||
| {% endif %} | |||
| <!--</div>--> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <script> | |||
| document.addEventListener('DOMContentLoaded', function () { | |||
| // Get all "navbar-burger" elements | |||
| var $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); | |||
| // Check if there are any navbar burgers | |||
| if ($navbarBurgers.length > 0) { | |||
| // Add a click event on each of them | |||
| $navbarBurgers.forEach(function ($el) { | |||
| $el.addEventListener('click', function () { | |||
| // Get the target from the "data-target" attribute | |||
| var target = $el.dataset.target; | |||
| var $target = document.getElementById(target); | |||
| // Toggle the class on both the "navbar-burger" and the "navbar-menu" | |||
| $el.classList.toggle('is-active'); | |||
| $target.classList.toggle('is-active'); | |||
| }); | |||
| }); | |||
| } | |||
| }); | |||
| </script> | |||
| </nav> | |||
| @ -1,49 +0,0 @@ | |||
| {% extends 'base.html' %} | |||
| {% block content %} | |||
| <div class="column is-4 is-offset-4"> | |||
| <h3>Añadir nuevo Álbum</h3> | |||
| <div class="box"> | |||
| <form method="POST" enctype="multipart/form-data" action="/add_album"> | |||
| <div class="field"> | |||
| <label for="name">Nombre:</label> | |||
| <div class="control"> | |||
| <input type="text" id="name" name="name" required> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <label for="artist">Artista:</label> | |||
| <div class="control"> | |||
| <input type="text" id="artist" name="artist" required> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <label for="year">Año:</label> | |||
| <div class="control"> | |||
| <input type="number" id="year" name="year" required> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <label for="cover_image">Cover Image:</label> | |||
| <div class="control"> | |||
| <input type="file" id="cover_image" name="coverimage"> | |||
| </div> | |||
| </div> | |||
| <div class="field is-grouped"> | |||
| <div class="control"> | |||
| <button type="submit" class="button is-link">Añadir álbum</button> | |||
| </div> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| {% endblock %} | |||
| @ -1,71 +0,0 @@ | |||
| {% extends 'base.html' %} | |||
| {% block content %} | |||
| <div class="column is-4 is-offset-4"> | |||
| <h3>Añadir nueva canción</h3> | |||
| <div class="box"> | |||
| <form method="POST" action="/add_song"> | |||
| <div class="field"> | |||
| <label for="pista">Nº de pista:</label> <!-- Nuevo campo --> | |||
| <div class="control"> | |||
| <input type="number" id="pista" name="pista" required> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <label for="title">Título:</label> | |||
| <div class="control"> | |||
| <input type="text" id="title" name="title" required> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <label for="author">Autor:</label> | |||
| <div class="control"> | |||
| <input type="text" id="author" name="author" required> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <label for="album_id">Álbum:</label> | |||
| <div class="control"> | |||
| <div class="select"> | |||
| <select id="album_id" name="album_id" required> | |||
| {% for album in albums %} | |||
| <option value="{{ album.id }}" data-artist="{{ album.artist }}">{{ album.name }} by {{ album.artist }}</option> | |||
| {% endfor %} | |||
| </select> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <label for="lyrics">Letra:</label> | |||
| <div class="control"> | |||
| <textarea id="lyrics" name="lyrics" required></textarea> | |||
| </div> | |||
| </div> | |||
| <div class="field is-grouped"> | |||
| <div class="control"> | |||
| <button type="submit" class="button is-link">Añadir canción</button> | |||
| </div> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| <script> | |||
| function updateAuthor() { | |||
| var albumSelect = document.getElementById("album_id"); | |||
| var selectedAlbum = albumSelect.options[albumSelect.selectedIndex]; | |||
| var artist = selectedAlbum.getAttribute("data-artist"); | |||
| document.getElementById("author").value = artist; | |||
| } | |||
| // Initialize the author field with the artist of the first album | |||
| document.addEventListener('DOMContentLoaded', function() { | |||
| updateAuthor(); | |||
| }); | |||
| </script> | |||
| </div> | |||
| {% endblock %} | |||
| @ -1,38 +0,0 @@ | |||
| {% extends 'base.html' %} | |||
| {% block content %} | |||
| <h2>{{ album.name }}</h2> | |||
| <p><strong>Artista:</strong> {{ album.artist }}</p> | |||
| <p><strong>Año:</strong> {{ album.year }}</p> | |||
| {% if album.cover_image %} | |||
| <p><img src="{{ url_for('paginas.uploaded_file', filename=album.cover_image) }}" alt="{{ album.name }}" style="width:200px;height:200px;"></p> | |||
| {% else %} | |||
| <p>No hay imágen disponible</p> | |||
| {% endif %} | |||
| <h3>Canciones en este álbum</h3> | |||
| {% if songs %} | |||
| <table id="songTable" class="display"> | |||
| <thead> | |||
| <tr> | |||
| <th>Pista</th> | |||
| <th>Título</th> | |||
| <th>Autor</th> | |||
| </tr> | |||
| </thead> | |||
| <tbody> | |||
| {% for song in songs %} | |||
| <tr> | |||
| <td>{{ song.pista }}</td> | |||
| <td><a href="{{ url_for('paginas.song', song_id=song.id) }}">{{ song.title }}</a></td> | |||
| <td>{{ song.author }}</td> | |||
| </tr> | |||
| {% endfor %} | |||
| </tbody> | |||
| </table> | |||
| {% else %} | |||
| <p>No songs found matching your query.</p> | |||
| {% endif %} | |||
| <a href="{{ url_for('paginas.index') }}">Volver al inicio</a> | |||
| {% endblock %} | |||
| @ -1,72 +0,0 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="UTF-8"> | |||
| <title>Mis letras de canciones</title> | |||
| <!-- <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">--> | |||
| <link rel="stylesheet" href="{{ url_for('static', filename='bulma.css') }}"> | |||
| <style> | |||
| .tabs-content li { | |||
| display: none; | |||
| list-style: none; | |||
| } | |||
| .tabs-content li.is-active { | |||
| display: block; | |||
| } | |||
| </style> | |||
| <!-- DataTables CSS --> | |||
| <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.5/css/jquery.dataTables.css"> | |||
| <script src="{{ url_for('static', filename='BulmaJS-0.12.2/dist/tabs.js') }}"></script> | |||
| </head> | |||
| <body> | |||
| {% include("_navegacion.html") %} | |||
| <section class="hero is-fullheight"> | |||
| <header> | |||
| {% block header %}{% endblock header %} | |||
| </header> | |||
| <div class="container has-text-centered mt-5"> | |||
| {% block content %}{% endblock %} | |||
| </div> | |||
| </section> | |||
| <!-- jQuery --> | |||
| <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> | |||
| <!-- DataTables JS --> | |||
| <script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.js"></script> | |||
| <script> | |||
| $(document).ready(function() { | |||
| $('#songTable').DataTable({ | |||
| "language": { | |||
| "url": "//cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/Spanish.json" | |||
| } | |||
| }); | |||
| $('#albumTable').DataTable({ | |||
| "language": { | |||
| "url": "//cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/Spanish.json" | |||
| } | |||
| }); | |||
| }); | |||
| function openTab(evt, tabName) { | |||
| var i, tabcontent, tablinks; | |||
| tabcontent = document.getElementsByClassName("tabcontent"); | |||
| for (i = 0; i < tabcontent.length; i++) { | |||
| tabcontent[i].style.display = "none"; | |||
| } | |||
| tablinks = document.getElementsByClassName("tablinks"); | |||
| for (i = 0; i < tablinks.length; i++) { | |||
| tablinks[i].className = tablinks[i].className.replace(" active", ""); | |||
| } | |||
| document.getElementById(tabName).style.display = "block"; | |||
| evt.currentTarget.className += " active"; | |||
| } | |||
| // Default open tab | |||
| document.addEventListener('DOMContentLoaded', function () { | |||
| document.getElementsByClassName('tablinks')[0].click(); | |||
| }); | |||
| </script> | |||
| </body> | |||
| </html> | |||
| @ -1,94 +0,0 @@ | |||
| {% extends 'base.html' %} | |||
| {% block content %} | |||
| <div class="tabs-wrapper"> | |||
| <div class="tabs is-toggle is-fullwidth" id="tabs"> | |||
| <!-- | |||
| <button class="tablinks" onclick="openTab(event, 'Songs')">Songs</button> | |||
| <button class="tablinks" onclick="openTab(event, 'Albums')">Albums</button> | |||
| --> | |||
| <ul> | |||
| <li class="is-active" id="tablinks"> | |||
| <a onclick="openTab(event, 'Songs')"> | |||
| <span class="icon is-small"><i class="fa fa-image"></i></span> | |||
| <span>Canciones</span> | |||
| </a> | |||
| </li> | |||
| <li id="tablinks"> | |||
| <a onclick="openTab(event, 'Albums')"> | |||
| <span class="icon is-small"><i class="fa fa-music"></i></span> | |||
| <span>Álbumes</span> | |||
| </a> | |||
| </li> | |||
| </ul> | |||
| </div> | |||
| <div class="tabs-content"> | |||
| <ul> | |||
| <li class="is-active"> | |||
| <h2>Lista de canciones</h2> | |||
| {% if songs %} | |||
| <table id="songTable" class="display"> | |||
| <thead> | |||
| <tr> | |||
| <th>Pista</th> | |||
| <th>Título</th> | |||
| <th>Autor</th> | |||
| <th>Álbum</th> | |||
| </tr> | |||
| </thead> | |||
| <tbody> | |||
| {% for song in songs %} | |||
| <tr> | |||
| <td>{{ song.pista }}</td> | |||
| <td><a href="{{ url_for('paginas.song', song_id=song.id) }}">{{ song.title }}</a></td> | |||
| <td>{{ song.author }}</td> | |||
| <td><a href="{{ url_for('paginas.album', album_id=song.album.id) }}">{{ song.album.name }}</a></td> | |||
| </tr> | |||
| {% endfor %} | |||
| </tbody> | |||
| </table> | |||
| {% else %} | |||
| <p>No songs found.</p> | |||
| {% endif %} | |||
| </li> | |||
| <li> | |||
| <h2>Lista de álbumes</h2> | |||
| {% if albums %} | |||
| <table id="albumTable" class="display"> | |||
| <thead> | |||
| <tr> | |||
| <th>Cover</th> | |||
| <th>Nombre</th> | |||
| <th>Artista</th> | |||
| <th>Año</th> | |||
| </tr> | |||
| </thead> | |||
| <tbody> | |||
| {% for album in albums %} | |||
| <tr> | |||
| <td> | |||
| {% if album.cover_image %} | |||
| <img src="{{ url_for('paginas.uploaded_file', filename=album.cover_image) }}" alt="{{ album.name }}" style="width:50px;height:50px;"> | |||
| {% else %} | |||
| Sin imágen | |||
| {% endif %} | |||
| </td> | |||
| <td><a href="{{ url_for('paginas.album', album_id=album.id) }}">{{ album.name }}</a></td> | |||
| <td>{{ album.artist }}</td> | |||
| <td>{{ album.year }}</td> | |||
| </tr> | |||
| {% endfor %} | |||
| </tbody> | |||
| </table> | |||
| {% else %} | |||
| <p>No albums found.</p> | |||
| {% endif %} | |||
| <hr> | |||
| <a href="{{ url_for('paginas.add_album') }}" class="button">Añadir nuevo álbum</a> | |||
| </li> | |||
| </ul> | |||
| </div> | |||
| </div> | |||
| {% endblock %} | |||
| @ -1,36 +0,0 @@ | |||
| {% extends "base.html" %} | |||
| {% block content %} | |||
| <div class="column is-4 is-offset-4"> | |||
| <h3 class="title">Login</h3> | |||
| <div class="box"> | |||
| {% with messages = get_flashed_messages() %} | |||
| {% if messages %} | |||
| <div class="notification is-danger"> | |||
| {{ messages[0] }} | |||
| </div> | |||
| {% endif %} | |||
| {% endwith %} | |||
| <form method="POST" action="/login"> | |||
| <div class="field"> | |||
| <div class="control"> | |||
| <input class="input is-large" type="text" name="username" placeholder="Tu correo" autofocus=""> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <div class="control"> | |||
| <input class="input is-large" type="password" name="password" placeholder="Tu contraseña"> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <label class="checkbox"> | |||
| <input type="checkbox"> | |||
| Recuerdame | |||
| </label> | |||
| </div> | |||
| <button class="button is-block is-info is-large is-fullwidth">Entrar</button> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| {% endblock %} | |||
| @ -1,50 +0,0 @@ | |||
| {% extends "base.html" %} | |||
| {% block content %} | |||
| <div class="column is-4 is-offset-4"> | |||
| <h3 class="title">Nuevo usuario</h3> | |||
| <div class="box"> | |||
| {% with messages = get_flashed_messages() %} | |||
| {% if messages %} | |||
| <div class="notification is-danger"> | |||
| {{ messages[0] }}. Go to <a href="{{ url_for('auth.login') }}">login page</a>. | |||
| </div> | |||
| {% endif %} | |||
| {% endwith %} | |||
| <form method="POST" action="/signup"> | |||
| <div class="field"> | |||
| <div class="control"> | |||
| <input class="input is-large" type="text" name="username" placeholder="Nombre" autofocus=""> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <div class="control"> | |||
| <input class="input is-large" type="password" name="password" placeholder="Password"> | |||
| </div> | |||
| </div> | |||
| <button class="button is-block is-info is-large is-fullwidth">Registrarse</button> | |||
| </form> | |||
| </div> | |||
| <div class="box"> | |||
| <article class="media"> | |||
| <div class="media-content"> | |||
| <div class="content"> | |||
| <h3> | |||
| Información importante. | |||
| </h3> | |||
| <p> | |||
| El correo se usará exclusivamente para informarte de que has hecho una reserva. | |||
| </p> | |||
| <p> | |||
| El nombre aparecerá en el listado de reservas. | |||
| </p> | |||
| </div> | |||
| </div> | |||
| </article> | |||
| </div> | |||
| </div> | |||
| {% endblock %} | |||
| @ -1,9 +0,0 @@ | |||
| {% extends 'base.html' %} | |||
| {% block content %} | |||
| <h2>{{ song.title }}</h2> | |||
| <p><strong>Autor:</strong> {{ song.author }}</p> | |||
| <p><strong>Año:</strong> {{ song.album.year }}</p> | |||
| <p><strong>Álbum:</strong> {{ song.album.name }}</p> | |||
| <pre>{{ song.lyrics }}</pre> | |||
| {% endblock %} | |||