mirror of
https://gitlab.com/parroquia-san-leandro/cancionero-web.git
synced 2024-12-22 00:33:33 +01:00
Rediseño de la interfaz y arreglos menores
- ¡Ahora con tema oscuro! Se activa según el navegador del usuario. - URL de audios simplificada. - Nuevos iconos para canciones con acordes/audios. - Enlaces de la cabecera actualizados. - Siempre mostramos los ajustes. - Insertar espacio forzoso para separar algunas palabras que se juntaban. - Soporte para canciones con dos líneas de acordes (e.g. Engrandece).
This commit is contained in:
parent
e838b066de
commit
03522304fa
15 changed files with 203 additions and 83 deletions
4
Makefile
4
Makefile
|
@ -14,11 +14,11 @@ public:
|
||||||
mkdir public
|
mkdir public
|
||||||
|
|
||||||
public/index.html: $(ALL_TEMPLATES) $(PY_SRC)
|
public/index.html: $(ALL_TEMPLATES) $(PY_SRC)
|
||||||
python3 src/latex_scanner.py --latex latex/cancionero.tex --audios audios/Canciones --other-latex latex/canciones/
|
python3 src/latex_scanner.py --latex latex/cancionero.tex --audios audios --other-latex latex/canciones/
|
||||||
|
|
||||||
public/audios: audios public
|
public/audios: audios public
|
||||||
rm -f public/audios
|
rm -f public/audios
|
||||||
ln -s ../audios/Canciones public/audios
|
#ln -s ../audios/Canciones public/audios
|
||||||
|
|
||||||
public/main.css: res/less/main.less res/less/colors.less
|
public/main.css: res/less/main.less res/less/colors.less
|
||||||
lessc $< $@
|
lessc $< $@
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
@nochordscolor: #FBB;
|
@background: #FFF;
|
||||||
@nochordscolor-hover: #FAA;
|
@background-dark: darken(@background, 100%);
|
||||||
@title: #369;
|
@title: #369;
|
||||||
|
@title-dark: lighten(@title, 50%);
|
||||||
@subtitle: #444;
|
@subtitle: #444;
|
||||||
|
@subtitle-dark: lighten(@subtitle, 100%);
|
||||||
@text: #333;
|
@text: #333;
|
||||||
|
@text-dark: lighten(@text, 100%);
|
||||||
@text-hover: #607D8B;
|
@text-hover: #607D8B;
|
||||||
|
@text-hover-dark: @text-hover;
|
||||||
@secondary: #EEE;
|
@secondary: #EEE;
|
||||||
|
@secondary-dark: #333;
|
||||||
@secondary-hover: #CCC;
|
@secondary-hover: #CCC;
|
||||||
|
@secondary-hover-dark: #444;
|
||||||
@chord-color: darkgreen;
|
@chord-color: darkgreen;
|
||||||
|
@chord-color-dark: lightgreen;
|
||||||
|
|
||||||
@transition: .5s;
|
@transition: .5s;
|
||||||
@border-radius: 4px;
|
@border-radius: 10px;
|
||||||
|
|
|
@ -7,24 +7,22 @@
|
||||||
color: inherit;
|
color: inherit;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
> li {
|
> li {
|
||||||
background-color: @secondary;
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
margin: .5em;
|
margin: .5em;
|
||||||
padding: .6em;
|
padding: .6em;
|
||||||
|
border: 1px solid @text;
|
||||||
border-radius: @border-radius;
|
border-radius: @border-radius;
|
||||||
.number {
|
@media (prefers-color-scheme: dark) {
|
||||||
font-weight: bolder;
|
border: 1px solid @text-dark;
|
||||||
color: black;
|
|
||||||
}
|
}
|
||||||
|
.number { font-weight: bolder; }
|
||||||
|
.name { flex-grow: 99; }
|
||||||
&:hover {
|
&:hover {
|
||||||
color: @text-hover;
|
background-color: @secondary;
|
||||||
background-color: @secondary-hover;
|
|
||||||
transition-duration: @transition;
|
transition-duration: @transition;
|
||||||
}
|
@media (prefers-color-scheme: dark) {
|
||||||
&.noChords {
|
background-color: @secondary-dark;
|
||||||
background-color: @nochordscolor;
|
|
||||||
&:hover {
|
|
||||||
color: @text-hover;
|
|
||||||
background-color: @nochordscolor-hover;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,9 +36,18 @@ ul.songs {
|
||||||
margin: .2em;
|
margin: .2em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span.noChords {
|
img.guitar-icon, img.music-icon {
|
||||||
background-color: @nochordscolor;
|
width: 1em;
|
||||||
padding: 0.3em 0.4em;
|
padding: 0 0.2em;
|
||||||
border-radius: @border-radius;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
}
|
||||||
|
img.guitar-icon {
|
||||||
|
/* Green color filter */
|
||||||
|
filter: invert(42%) sepia(93%) saturate(1352%) hue-rotate(55deg) brightness(119%) contrast(119%);
|
||||||
|
}
|
||||||
|
img.music-icon {
|
||||||
|
/* Orange color filter */
|
||||||
|
filter: invert(46%) sepia(100%) saturate(681%) hue-rotate(360deg) brightness(106%) contrast(105%);
|
||||||
|
}
|
||||||
|
p { img.guitar-icon, img.music-icon {
|
||||||
|
vertical-align: -0.25em;
|
||||||
|
}}
|
||||||
|
|
|
@ -6,8 +6,14 @@ h1 {
|
||||||
width: max-content;
|
width: max-content;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
color: @title-dark;
|
||||||
|
}
|
||||||
> a, > a:hover, > a:active, > a:visited {
|
> a, > a:hover, > a:active, > a:visited {
|
||||||
color: @title;
|
color: @title;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
color: @title-dark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +21,9 @@ h2, h3 {
|
||||||
color: @subtitle;
|
color: @subtitle;
|
||||||
font-weight: lighter;
|
font-weight: lighter;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
color: @subtitle-dark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
|
@ -24,8 +33,13 @@ footer {
|
||||||
body {
|
body {
|
||||||
font-family: Helvetica, Arial, sans-serif;
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
color: @text;
|
color: @text;
|
||||||
|
background: @background;
|
||||||
max-width: 75em;
|
max-width: 75em;
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
color: @text-dark;
|
||||||
|
background: @background-dark;
|
||||||
|
}
|
||||||
@media (min-width: 75em + 1em) {
|
@media (min-width: 75em + 1em) {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +57,9 @@ nav {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nav a > span {
|
||||||
|
border-width: 4px;
|
||||||
|
}
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
> span {
|
> span {
|
||||||
|
@ -50,11 +67,20 @@ a {
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
margin: 0.2em;
|
margin: 0.2em;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: @secondary;
|
border-radius: @border-radius * 5;
|
||||||
border-radius: @border-radius;
|
border: 1px solid @text;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
color: @text-dark;
|
||||||
|
border-color: @text-dark;
|
||||||
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
background: @secondary-hover;
|
background: @secondary-hover;
|
||||||
transition-duration: @transition;
|
transition-duration: @transition;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
background: @secondary-hover-dark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
&#nav-web { border-color: #6ecf00; }
|
||||||
|
&#nav-audios { border-color: orange; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,6 @@ table.chordedline {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.song div {
|
|
||||||
padding: 0.5em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chordedline td {
|
.chordedline td {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
|
@ -16,11 +12,21 @@ table.chordedline {
|
||||||
.chord {
|
.chord {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
color: @chord-color;
|
color: @chord-color;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
color: @chord-color-dark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div.chorus {
|
.song div {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.chorus, p.chorus {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border-left: black 2px solid;
|
border-left: @text 2px solid;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
border-left: @text-dark 2px solid;
|
||||||
|
}
|
||||||
padding-left: 0.5em;
|
padding-left: 0.5em;
|
||||||
div {
|
div {
|
||||||
padding-left: 0.5em;
|
padding-left: 0.5em;
|
||||||
|
@ -37,6 +43,10 @@ div.chorus {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 1em;
|
width: 1em;
|
||||||
height: 2em;
|
height: 2em;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
/* Black to white filter for svgs */
|
||||||
|
filter: invert(100%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.lrep {
|
.lrep {
|
||||||
|
@ -63,10 +73,18 @@ button, select#transposeSelect {
|
||||||
padding: .4em;
|
padding: .4em;
|
||||||
border-style: none;
|
border-style: none;
|
||||||
border-radius: @border-radius;
|
border-radius: @border-radius;
|
||||||
|
color: @text;
|
||||||
background-color: @secondary;
|
background-color: @secondary;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
color: @text-dark;
|
||||||
|
background-color: @secondary-dark;
|
||||||
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: @secondary-hover;
|
background-color: @secondary-hover;
|
||||||
transition-duration: @transition;
|
transition-duration: @transition;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
background-color: @secondary-hover-dark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,4 +93,7 @@ select#transposeSelect {
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: black;
|
color: black;
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
color: @text-dark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
1
res/static/file-audio.svg
Normal file
1
res/static/file-audio.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V160H256c-17.7 0-32-14.3-32-32V0H64zM256 0V128H384L256 0zm2 226.3c37.1 22.4 62 63.1 62 109.7s-24.9 87.3-62 109.7c-7.6 4.6-17.4 2.1-22-5.4s-2.1-17.4 5.4-22C269.4 401.5 288 370.9 288 336s-18.6-65.5-46.5-82.3c-7.6-4.6-10-14.4-5.4-22s14.4-10 22-5.4zm-91.9 30.9c6 2.5 9.9 8.3 9.9 14.8V400c0 6.5-3.9 12.3-9.9 14.8s-12.9 1.1-17.4-3.5L113.4 376H80c-8.8 0-16-7.2-16-16V312c0-8.8 7.2-16 16-16h33.4l35.3-35.3c4.6-4.6 11.5-5.9 17.4-3.5zm51 34.9c6.6-5.9 16.7-5.3 22.6 1.3C249.8 304.6 256 319.6 256 336s-6.2 31.4-16.3 42.7c-5.9 6.6-16 7.1-22.6 1.3s-7.1-16-1.3-22.6c5.1-5.7 8.1-13.1 8.1-21.3s-3.1-15.7-8.1-21.3c-5.9-6.6-5.3-16.7 1.3-22.6z"/></svg>
|
After Width: | Height: | Size: 946 B |
1
res/static/gear.svg
Normal file
1
res/static/gear.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M495.9 166.6c3.2 8.7 .5 18.4-6.4 24.6l-43.3 39.4c1.1 8.3 1.7 16.8 1.7 25.4s-.6 17.1-1.7 25.4l43.3 39.4c6.9 6.2 9.6 15.9 6.4 24.6c-4.4 11.9-9.7 23.3-15.8 34.3l-4.7 8.1c-6.6 11-14 21.4-22.1 31.2c-5.9 7.2-15.7 9.6-24.5 6.8l-55.7-17.7c-13.4 10.3-28.2 18.9-44 25.4l-12.5 57.1c-2 9.1-9 16.3-18.2 17.8c-13.8 2.3-28 3.5-42.5 3.5s-28.7-1.2-42.5-3.5c-9.2-1.5-16.2-8.7-18.2-17.8l-12.5-57.1c-15.8-6.5-30.6-15.1-44-25.4L83.1 425.9c-8.8 2.8-18.6 .3-24.5-6.8c-8.1-9.8-15.5-20.2-22.1-31.2l-4.7-8.1c-6.1-11-11.4-22.4-15.8-34.3c-3.2-8.7-.5-18.4 6.4-24.6l43.3-39.4C64.6 273.1 64 264.6 64 256s.6-17.1 1.7-25.4L22.4 191.2c-6.9-6.2-9.6-15.9-6.4-24.6c4.4-11.9 9.7-23.3 15.8-34.3l4.7-8.1c6.6-11 14-21.4 22.1-31.2c5.9-7.2 15.7-9.6 24.5-6.8l55.7 17.7c13.4-10.3 28.2-18.9 44-25.4l12.5-57.1c2-9.1 9-16.3 18.2-17.8C227.3 1.2 241.5 0 256 0s28.7 1.2 42.5 3.5c9.2 1.5 16.2 8.7 18.2 17.8l12.5 57.1c15.8 6.5 30.6 15.1 44 25.4l55.7-17.7c8.8-2.8 18.6-.3 24.5 6.8c8.1 9.8 15.5 20.2 22.1 31.2l4.7 8.1c6.1 11 11.4 22.4 15.8 34.3zM256 336a80 80 0 1 0 0-160 80 80 0 1 0 0 160z"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
res/static/guitar.svg
Normal file
1
res/static/guitar.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M465 7c-9.4-9.4-24.6-9.4-33.9 0L383 55c-2.4 2.4-4.3 5.3-5.5 8.5l-15.4 41-77.5 77.6c-45.1-29.4-99.3-30.2-131 1.6c-11 11-18 24.6-21.4 39.6c-3.7 16.6-19.1 30.7-36.1 31.6c-25.6 1.3-49.3 10.7-67.3 28.6C-16 328.4-7.6 409.4 47.5 464.5s136.1 63.5 180.9 18.7c17.9-17.9 27.4-41.7 28.6-67.3c.9-17 15-32.3 31.6-36.1c15-3.4 28.6-10.5 39.6-21.4c31.8-31.8 31-85.9 1.6-131l77.6-77.6 41-15.4c3.2-1.2 6.1-3.1 8.5-5.5l48-48c9.4-9.4 9.4-24.6 0-33.9L465 7zM208 256a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"/></svg>
|
After Width: | Height: | Size: 727 B |
1
res/static/music.svg
Normal file
1
res/static/music.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M499.1 6.3c8.1 6 12.9 15.6 12.9 25.7v72V368c0 44.2-43 80-96 80s-96-35.8-96-80s43-80 96-80c11.2 0 22 1.6 32 4.6V147L192 223.8V432c0 44.2-43 80-96 80s-96-35.8-96-80s43-80 96-80c11.2 0 22 1.6 32 4.6V200 128c0-14.1 9.3-26.6 22.8-30.7l320-96c9.7-2.9 20.2-1.1 28.3 5z"/></svg>
|
After Width: | Height: | Size: 510 B |
|
@ -1,6 +1,6 @@
|
||||||
<footer>
|
<footer>
|
||||||
<p>
|
<p>
|
||||||
© 2020 Carlos Galindo, Parroquia San Leandro
|
© 2023 Carlos Galindo, Parroquia San Leandro
|
||||||
<a href="https://gitlab.com/parroquia-san-leandro/cancionero-web"><span>Código fuente</span></a>
|
<a href="https://gitlab.com/parroquia-san-leandro/cancionero-web"><span>Código fuente</span></a>
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
<h1><a href="{{ path }}">Cancionero San Leandro</a></h1>
|
<h1><a href="{{ path }}">Cancionero San Leandro</a></h1>
|
||||||
<nav class="nav">
|
<nav class="nav">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://sanleandro-obispo.net/"><span>Parroquia San Leandro</span></a></li>
|
<li><a href="https://sanleandrovalencia.es/"><span id="nav-web">Parroquia San Leandro</span></a></li>
|
||||||
<li><a href="https://nube.sanleandro-obispo.net/s/X23Jzz5A6dpCfr2"><span>Grabaciones</span></a></li>
|
<li><a href="https://nube.sanleandrovalencia.es/s/X23Jzz5A6dpCfr2"><span id="nav-audios">Grabaciones</span></a></li>
|
||||||
<li><a href="https://sanleandro-obispo.net/cancionero/"><span>Cancionero en PDF</span></a></li>
|
<li><a href="https://sanleandrovalencia.es/cancionero/"><span>Cancionero en PDF</span></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
@ -15,17 +15,25 @@
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
Las canciones sin acordes están marcadas en <span class="noChords">rojo</span>.
|
<p><strong>Leyenda</strong>: <img src="music.svg" class="music-icon"> tiene música grabada; <img src="guitar.svg" class="guitar-icon"> tiene acordes.</p>
|
||||||
<ol class="songs">
|
<ol class="songs">
|
||||||
{% for category, songs in sorted_categories.items %}
|
{% for category, songs in sorted_categories.items %}
|
||||||
<h3 id="{{ category|slugify }}">{{ category|title }}</h3>
|
<h3 id="{{ category|slugify }}">{{ category|title }}</h3>
|
||||||
{% for song in songs %}
|
{% for song in songs %}
|
||||||
<a href="{{ song.url }}">
|
<a href="{{ song.url }}">
|
||||||
<li {% if not song.chorded %}class="noChords" {% endif %}>
|
<li>
|
||||||
<span class="number">{{ song.number }}.</span>
|
<span class="number">{{ song.number }}.</span>
|
||||||
{{ song.name }}
|
<span class="name">
|
||||||
{% if song.author %} por {{ song.author }} {% endif %}
|
{{ song.name }}
|
||||||
{% if song.origin %} basada en {{ song.origin }} {% endif %}
|
{% if song.author %} por {{ song.author }} {% endif %}
|
||||||
|
{% if song.origin %} basada en {{ song.origin }} {% endif %}
|
||||||
|
</span>
|
||||||
|
{% if song.has_audios %}
|
||||||
|
<img src="music.svg" class="music-icon filter-green">
|
||||||
|
{% endif %}
|
||||||
|
{% if song.chorded %}
|
||||||
|
<img src="guitar.svg" class="guitar-icon filter-green">
|
||||||
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -34,4 +42,4 @@
|
||||||
</main>
|
</main>
|
||||||
{% include "footer.html" %}
|
{% include "footer.html" %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -16,8 +16,7 @@
|
||||||
{% if song.origin %}
|
{% if song.origin %}
|
||||||
<span>basada en: <strong>{{ song.origin }}</strong></span>
|
<span>basada en: <strong>{{ song.origin }}</strong></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<details>
|
<h3>Ajustes</h3>
|
||||||
<summary><h3 style="display: inline-block;">Ajustes</h3></summary>
|
|
||||||
<div>
|
<div>
|
||||||
<label>Cambiar tamaño de letra </label>
|
<label>Cambiar tamaño de letra </label>
|
||||||
<button class="small" onclick="size(-1)">-</button>
|
<button class="small" onclick="size(-1)">-</button>
|
||||||
|
@ -29,7 +28,7 @@
|
||||||
<label><input id="showChords" type="checkbox" checked onchange="showChords(this.checked)"/> Mostrar acordes</label>
|
<label><input id="showChords" type="checkbox" checked onchange="showChords(this.checked)"/> Mostrar acordes</label>
|
||||||
</div>
|
</div>
|
||||||
<div id="transposeControls" class="showChords">
|
<div id="transposeControls" class="showChords">
|
||||||
<label>Transponer acordes </label>
|
<label for="transposeSelect">Transponer acordes </label>
|
||||||
<button class="small" onclick="transposeAdd(-2)">-2</button>
|
<button class="small" onclick="transposeAdd(-2)">-2</button>
|
||||||
<button class="small" onclick="transposeAdd(-1)">-1</button>
|
<button class="small" onclick="transposeAdd(-1)">-1</button>
|
||||||
<select id="transposeSelect" disabled>
|
<select id="transposeSelect" disabled>
|
||||||
|
@ -58,16 +57,15 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</details>
|
|
||||||
<h3>Canción</h3>
|
<h3>Canción</h3>
|
||||||
<div id="wholeSongDiv">
|
<div id="wholeSongDiv">
|
||||||
<div id="songLyrics" class="showLyrics" style="display: none;">
|
<div id="songLyrics" class="showLyrics" style="display: none;">
|
||||||
{% for verse in song.verses %}
|
{% for verse in song.verses %}
|
||||||
<div class="{{ verse.kind }}">
|
<p class="{{ verse.kind }}">
|
||||||
{% for line in verse.lines %}
|
{% for line in verse.lines %}
|
||||||
{{ line }}<br/>
|
{{ line }}<br/>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div id="songChords" class="showChords">
|
<div id="songChords" class="showChords">
|
||||||
|
@ -82,13 +80,45 @@
|
||||||
{% if chord.class %}
|
{% if chord.class %}
|
||||||
<span class="{{ chord.class }}"></span>
|
<span class="{{ chord.class }}"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for c in chord.chord.items %}
|
{% if chord.chord.trfmt == "normal" %}
|
||||||
{% if c.chord %}
|
{% for c in chord.chord.items_t %}
|
||||||
<span class="c">{{ c.text|safe }}</span>
|
{% if c.chord %}
|
||||||
{% else %}
|
<span class="c">{{ c.text|safe }}</span>
|
||||||
<span>{{ c.text|safe }}</span>
|
{% else %}
|
||||||
|
<span>{{ c.text|safe }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if chord.chord.trfmt == "double" %}
|
||||||
|
<span>
|
||||||
|
{% for c in chord.chord.items_n %}
|
||||||
|
{% if c.chord %}
|
||||||
|
<span class="c">{{ c.text|safe }}</span>
|
||||||
|
{% else %}
|
||||||
|
<span>{{ c.text|safe }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<br/>
|
||||||
|
{% for c in chord.chord.items_t %}
|
||||||
|
{% if c.chord %}
|
||||||
|
<span class="c">{{ c.text|safe }}</span>
|
||||||
|
{% else %}
|
||||||
|
<span>{{ c.text|safe }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<span/>
|
||||||
|
{% endif %}
|
||||||
|
{% if chord.chord.trfmt == "hover" %}
|
||||||
|
<span>
|
||||||
|
{% for c in chord.chord.items_n %}
|
||||||
|
{% if c.chord %}
|
||||||
|
<span class="c">{{ c.text|safe }}</span>
|
||||||
|
{% else %}
|
||||||
|
<span>{{ c.text|safe }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<br/> </span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="lyric">
|
<tr class="lyric">
|
||||||
|
|
|
@ -90,6 +90,7 @@ class SongLoader:
|
||||||
memorizing = False
|
memorizing = False
|
||||||
replay_index = 0
|
replay_index = 0
|
||||||
transpose = 0
|
transpose = 0
|
||||||
|
trfmt = "normal"
|
||||||
|
|
||||||
for line in open(song_file, "r").readlines():
|
for line in open(song_file, "r").readlines():
|
||||||
# Remove newline
|
# Remove newline
|
||||||
|
@ -117,13 +118,11 @@ class SongLoader:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Command lookup
|
# Command lookup
|
||||||
re_transpose_match = re.match(r"\\transpose *?{(-?\d+?)}", remain)
|
if re_transpose_match := re.match(r"\\transpose *?{(-?\d+?)}", remain):
|
||||||
if re_transpose_match:
|
|
||||||
text = beginning + text[i + len(re_transpose_match.group(0)):]
|
text = beginning + text[i + len(re_transpose_match.group(0)):]
|
||||||
transpose = int(re_transpose_match.group(1))
|
transpose = int(re_transpose_match.group(1))
|
||||||
continue
|
continue
|
||||||
re_song_begin_match = re.match(r"\\beginsong *?{(.*?)}(\[.*?])?", remain)
|
if re_song_begin_match := re.match(r"\\beginsong *?{(.*?)}(\[.*?])?", remain):
|
||||||
if re_song_begin_match:
|
|
||||||
text = beginning + text[i + len(re_song_begin_match.group(0)):]
|
text = beginning + text[i + len(re_song_begin_match.group(0)):]
|
||||||
if current_song is not None:
|
if current_song is not None:
|
||||||
print("error end-begin song! %s at %s" % (line, song_file))
|
print("error end-begin song! %s at %s" % (line, song_file))
|
||||||
|
@ -135,6 +134,7 @@ class SongLoader:
|
||||||
category=self.category,
|
category=self.category,
|
||||||
latex_file=song_file[song_file.index('/') + 1:])
|
latex_file=song_file[song_file.index('/') + 1:])
|
||||||
transpose = 0
|
transpose = 0
|
||||||
|
trfmt = "normal"
|
||||||
memory = None
|
memory = None
|
||||||
memorizing = False
|
memorizing = False
|
||||||
replay_index = 0
|
replay_index = 0
|
||||||
|
@ -148,8 +148,7 @@ class SongLoader:
|
||||||
current_song = None
|
current_song = None
|
||||||
self.index += 1
|
self.index += 1
|
||||||
continue
|
continue
|
||||||
re_verse_cmd_match = re.match(r"\\(begin|end)(verse|chorus)", remain)
|
if re_verse_cmd_match := re.match(r"\\(begin|end)(verse|chorus)", remain):
|
||||||
if re_verse_cmd_match:
|
|
||||||
text = beginning + text[i + len(re_verse_cmd_match.group(0)):]
|
text = beginning + text[i + len(re_verse_cmd_match.group(0)):]
|
||||||
is_chorus = re_verse_cmd_match.group(2) == "chorus"
|
is_chorus = re_verse_cmd_match.group(2) == "chorus"
|
||||||
if current_song is None:
|
if current_song is None:
|
||||||
|
@ -170,8 +169,7 @@ class SongLoader:
|
||||||
current_song.add_verse(current_verse)
|
current_song.add_verse(current_verse)
|
||||||
current_verse = None
|
current_verse = None
|
||||||
continue
|
continue
|
||||||
re_capo_match = re.match(r"\\capo{(\d+?)}", remain)
|
if (re_capo_match := re.match(r"\\capo{(\d+?)}", remain)) and current_song:
|
||||||
if re_capo_match and current_song:
|
|
||||||
text = beginning + text[i + len(re_capo_match.group(0)):]
|
text = beginning + text[i + len(re_capo_match.group(0)):]
|
||||||
current_song.set_capo(int(re_capo_match.group(1)))
|
current_song.set_capo(int(re_capo_match.group(1)))
|
||||||
continue
|
continue
|
||||||
|
@ -182,8 +180,7 @@ class SongLoader:
|
||||||
ignore = True
|
ignore = True
|
||||||
text = beginning + text[i + len("\\else"):]
|
text = beginning + text[i + len("\\else"):]
|
||||||
continue
|
continue
|
||||||
re_echo_match = re.match(r"\\echo[ \t]*?{((.|{.*?})*?)}", remain)
|
if re_echo_match := re.match(r"\\echo[ \t]*?{((.|{.*?})*?)}", remain):
|
||||||
if re_echo_match:
|
|
||||||
text = beginning + re_echo_match.group(1) + "\\echoend" + text[i + len(re_echo_match.group(0)):]
|
text = beginning + re_echo_match.group(1) + "\\echoend" + text[i + len(re_echo_match.group(0)):]
|
||||||
extra_put(extras, i, "echo")
|
extra_put(extras, i, "echo")
|
||||||
continue
|
continue
|
||||||
|
@ -191,10 +188,9 @@ class SongLoader:
|
||||||
text = beginning + text[i + len("\\echoend"):]
|
text = beginning + text[i + len("\\echoend"):]
|
||||||
extra_put(extras, i, "echo")
|
extra_put(extras, i, "echo")
|
||||||
continue
|
continue
|
||||||
re_chord_match = re.match(r"\\\[(.+?)]", remain)
|
if re_chord_match := re.match(r"\\\[(.+?)]", remain):
|
||||||
if re_chord_match:
|
|
||||||
text = beginning + text[i + len(re_chord_match.group(0)):]
|
text = beginning + text[i + len(re_chord_match.group(0)):]
|
||||||
c = Chord(re_chord_match.group(1), transpose)
|
c = Chord(re_chord_match.group(1), transpose, trfmt)
|
||||||
extra_put(extras, i, "chord", c)
|
extra_put(extras, i, "chord", c)
|
||||||
if memorizing:
|
if memorizing:
|
||||||
memory.append(c)
|
memory.append(c)
|
||||||
|
@ -205,13 +201,11 @@ class SongLoader:
|
||||||
extra_put(extras, i, "chord", memory[replay_index])
|
extra_put(extras, i, "chord", memory[replay_index])
|
||||||
replay_index += 1
|
replay_index += 1
|
||||||
continue
|
continue
|
||||||
re_dir_rep_match = re.match(r"\\([lr]rep)", remain)
|
if re_dir_rep_match := re.match(r"\\([lr]rep)", remain):
|
||||||
if re_dir_rep_match:
|
|
||||||
text = beginning + text[i + len(re_dir_rep_match.group(0)):]
|
text = beginning + text[i + len(re_dir_rep_match.group(0)):]
|
||||||
extra_put(extras, i, "dir-rep", re_dir_rep_match.group(1))
|
extra_put(extras, i, "dir-rep", re_dir_rep_match.group(1))
|
||||||
continue
|
continue
|
||||||
re_rep_match = re.match(r"\\rep{(\d+?)}", remain)
|
if re_rep_match := re.match(r"\\rep{(\d+?)}", remain):
|
||||||
if re_rep_match:
|
|
||||||
text = beginning + text[i + len(re_rep_match.group(0)):]
|
text = beginning + text[i + len(re_rep_match.group(0)):]
|
||||||
extra_put(extras, i, 'rep', int(re_rep_match.group(1)))
|
extra_put(extras, i, 'rep', int(re_rep_match.group(1)))
|
||||||
continue
|
continue
|
||||||
|
@ -224,6 +218,19 @@ class SongLoader:
|
||||||
text = beginning + text[i + len("\\replay"):]
|
text = beginning + text[i + len("\\replay"):]
|
||||||
replay_index = 0
|
replay_index = 0
|
||||||
continue
|
continue
|
||||||
|
# Double or single transpose mode
|
||||||
|
if re_trfmt := re.match(r"\\renewcommand{\\trchordformat}\[2\]{\\vbox{\\hbox{#1}\\hbox{#2}}}", remain):
|
||||||
|
text = beginning + text[i + len(re_trfmt.group(0)):]
|
||||||
|
trfmt = "double"
|
||||||
|
continue
|
||||||
|
if re_trfmt := re.match(r"\\renewcommand{\\trchordformat}\[2\]{\\vbox{\\hbox{#1}\\hbox{}}}", remain):
|
||||||
|
text = beginning + text[i + len(re_trfmt.group(0)):]
|
||||||
|
trfmt = "hover"
|
||||||
|
continue
|
||||||
|
if re_trfmt := re.match(r"\\renewcommand{\\trchordformat}\[2\]{\\hbox{#2}}", remain):
|
||||||
|
text = beginning + text[i + len(re_trfmt.group(0)):]
|
||||||
|
trfmt = "normal"
|
||||||
|
continue
|
||||||
# Command lookup end, removing any unrecognized command
|
# Command lookup end, removing any unrecognized command
|
||||||
re_macro_match = re.match(r"\\([^ \t{\[]+)[ \t]*?({.*?}|\[.*?])*", remain)
|
re_macro_match = re.match(r"\\([^ \t{\[]+)[ \t]*?({.*?}|\[.*?])*", remain)
|
||||||
if re_macro_match:
|
if re_macro_match:
|
||||||
|
|
38
src/model.py
38
src/model.py
|
@ -40,7 +40,7 @@ class Song:
|
||||||
self.verses.append(verse)
|
self.verses.append(verse)
|
||||||
|
|
||||||
def url(self):
|
def url(self):
|
||||||
return "%03d %s" % (self.number, self.name.replace("¿", "").replace("?", ""))
|
return "%03d %s/" % (self.number, self.name.replace("¿", "").replace("?", ""))
|
||||||
|
|
||||||
def chorded(self):
|
def chorded(self):
|
||||||
for v in self.verses:
|
for v in self.verses:
|
||||||
|
@ -48,6 +48,9 @@ class Song:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def has_audios(self):
|
||||||
|
return len(self.audios) > 0
|
||||||
|
|
||||||
|
|
||||||
class Verse:
|
class Verse:
|
||||||
def __init__(self, is_chorus=False):
|
def __init__(self, is_chorus=False):
|
||||||
|
@ -149,6 +152,7 @@ class Line:
|
||||||
self.lyric_arr.append(Line.ECHO_BEGIN if inside_echo else '')
|
self.lyric_arr.append(Line.ECHO_BEGIN if inside_echo else '')
|
||||||
mid = True
|
mid = True
|
||||||
self.lyric_arr[-1] += self.text[i]
|
self.lyric_arr[-1] += self.text[i]
|
||||||
|
self.lyric_arr = [re.sub(r'^ | $', ' ', l) for l in self.lyric_arr]
|
||||||
self.lyric_arr = [l if l != "" else " " for l in self.lyric_arr]
|
self.lyric_arr = [l if l != "" else " " for l in self.lyric_arr]
|
||||||
|
|
||||||
def remove_brackets(self):
|
def remove_brackets(self):
|
||||||
|
@ -162,8 +166,8 @@ class Line:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def chord_eng2lat(text):
|
def chord_eng2lat(text, transpose = 0):
|
||||||
return Chord.CHORDS_LAT[Chord.ENG_INDEX[text]]
|
return Chord.CHORDS_LAT[(Chord.ENG_INDEX[text] + transpose + len(Chord.CHORDS_LAT)) % len(Chord.CHORDS_LAT)]
|
||||||
|
|
||||||
|
|
||||||
class Chord:
|
class Chord:
|
||||||
|
@ -172,28 +176,34 @@ class Chord:
|
||||||
CHORDS_ENG = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B&', 'B']
|
CHORDS_ENG = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B&', 'B']
|
||||||
ENG_INDEX = {'C': 0, 'C#': 1, 'D&': 1, 'D': 2, 'D#': 3, 'E&': 3, 'E': 4, 'F&': 4, 'F': 5, 'E#': 5, 'F#': 6, 'G&': 6, 'G': 7, 'G#': 8, 'A&': 8, 'A': 9, 'A#': 10, 'B&': 10, 'B': 11, 'C&': 11, 'B#': 0}
|
ENG_INDEX = {'C': 0, 'C#': 1, 'D&': 1, 'D': 2, 'D#': 3, 'E&': 3, 'E': 4, 'F&': 4, 'F': 5, 'E#': 5, 'F#': 6, 'G&': 6, 'G': 7, 'G#': 8, 'A&': 8, 'A': 9, 'A#': 10, 'B&': 10, 'B': 11, 'C&': 11, 'B#': 0}
|
||||||
|
|
||||||
def __init__(self, text, base_transpose=0):
|
def __init__(self, text, transpose = 0, trfmt = "normal"):
|
||||||
self.text = text + " "
|
self.text = text + " "
|
||||||
self.items = []
|
self.items_n = [] # normal version
|
||||||
self.base_transpose = base_transpose
|
self.items_t = [] # transposed version
|
||||||
|
self.transpose = transpose
|
||||||
|
self.trfmt = trfmt
|
||||||
ignore = False
|
ignore = False
|
||||||
for i, char in enumerate(text):
|
for i, char in enumerate(text):
|
||||||
if ignore:
|
if ignore:
|
||||||
ignore = False
|
ignore = False
|
||||||
continue
|
continue
|
||||||
if "A" <= char <= "G":
|
if "A" <= char <= "G":
|
||||||
if len(self.items) > 0 and not self.items[-1]['text'].endswith(" "):
|
if len(self.items_n) > 0 and not self.items_n[-1]['text'].endswith(" "):
|
||||||
self.items[-1]['text'] += " "
|
self.items_n[-1]['text'] += " "
|
||||||
|
self.items_t[-1]['text'] += " "
|
||||||
if len(text) > i + 1 and (text[i + 1] == "#" or text[i + 1] == "&"):
|
if len(text) > i + 1 and (text[i + 1] == "#" or text[i + 1] == "&"):
|
||||||
self.items.append({'text': chord_eng2lat(char + text[i + 1]), 'chord': True})
|
self.items_n.append({'text': chord_eng2lat(char + text[i + 1]), 'chord': True})
|
||||||
|
self.items_t.append({'text': chord_eng2lat(char + text[i + 1], transpose), 'chord': True})
|
||||||
ignore = True
|
ignore = True
|
||||||
else:
|
else:
|
||||||
self.items.append({'text': chord_eng2lat(char), 'chord': True})
|
self.items_n.append({'text': chord_eng2lat(char), 'chord': True})
|
||||||
|
self.items_t.append({'text': chord_eng2lat(char, transpose), 'chord': True})
|
||||||
else:
|
else:
|
||||||
self.items.append({'text': char, 'chord': False})
|
self.items_n.append({'text': char, 'chord': False})
|
||||||
if len(self.items) > 0 and not self.items[-1]['text'].endswith(" "):
|
self.items_t.append({'text': char, 'chord': False})
|
||||||
self.items[-1]['text'] += " "
|
if len(self.items_n) > 0 and not self.items_n[-1]['text'].endswith(" "):
|
||||||
|
self.items_n[-1]['text'] += " "
|
||||||
|
self.items_t[-1]['text'] += " "
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.text
|
return self.text
|
||||||
|
|
Loading…
Reference in a new issue