From f816423524c87a2cb811d7c3285bb2209abb905f Mon Sep 17 00:00:00 2001 From: WebOfPies <70017511+webofpies@users.noreply.github.com> Date: Thu, 7 Dec 2023 19:44:01 +0400 Subject: [PATCH] audio player first pass --- lute/static/css/player-styles.css | 361 ++++++++++++++++++++++++++++ lute/static/icn/bookmark-delete.svg | 13 + lute/static/icn/bookmark-next.svg | 4 + lute/static/icn/bookmark-prev.svg | 4 + lute/static/icn/bookmark-save.svg | 12 + lute/static/icn/ff.svg | 13 + lute/static/icn/pause.svg | 13 + lute/static/icn/play.svg | 12 + lute/static/icn/rewind.svg | 13 + lute/static/icn/speed.svg | 5 + lute/static/icn/stop.svg | 12 + lute/static/icn/volume-off.svg | 13 + lute/static/icn/volume-up.svg | 14 ++ lute/static/js/player.js | 280 +++++++++++++++++++++ lute/templates/base.html | 6 +- lute/templates/index.html | 51 ++-- lute/templates/read/index.html | 310 ++++++++++++++++-------- 17 files changed, 1014 insertions(+), 122 deletions(-) create mode 100644 lute/static/css/player-styles.css create mode 100644 lute/static/icn/bookmark-delete.svg create mode 100644 lute/static/icn/bookmark-next.svg create mode 100644 lute/static/icn/bookmark-prev.svg create mode 100644 lute/static/icn/bookmark-save.svg create mode 100644 lute/static/icn/ff.svg create mode 100644 lute/static/icn/pause.svg create mode 100644 lute/static/icn/play.svg create mode 100644 lute/static/icn/rewind.svg create mode 100644 lute/static/icn/speed.svg create mode 100644 lute/static/icn/stop.svg create mode 100644 lute/static/icn/volume-off.svg create mode 100644 lute/static/icn/volume-up.svg create mode 100644 lute/static/js/player.js diff --git a/lute/static/css/player-styles.css b/lute/static/css/player-styles.css new file mode 100644 index 00000000..2651defe --- /dev/null +++ b/lute/static/css/player-styles.css @@ -0,0 +1,361 @@ +.audio-player-container { + margin: 0 20px 30px 20px; + + border: 2px solid #d7e6f4; + border-radius: 5px; + padding: 0.9rem; + background-color: aliceblue; + + --audio-color-1: #5abaf4; +} + +.audio-player-top-container { + display: grid; + grid-template-columns: min-content 2.2fr min-content; + align-items: center; + + gap: 2%; +} + +.play-btn-container { + padding: 0.9rem; + background-color: #ddf3fc; + border-radius: 50%; +} + +.audio-player-timeline-container { + width: 100%; + /* for marker overlay */ + position: relative; +} + +.audio-player-timeline-container-grid { + display: grid; + grid-template-columns: 1fr min-content; + align-items: center; + gap: 2%; + background-color: #ddf3fc; + padding-left: 0.8rem; + padding-top: 0.8rem; + padding-bottom: 0.8rem; + padding-right: 0.8rem; + border-radius: 5px; +} + +#myfile { + display: none; +} + +.audio-label { + cursor: pointer; +} + +#play-btn { + /* background-image: url("/static/icn/play.svg"); */ + /* background-size: 70%; */ + /* content: ""; */ + background: url("/static/icn/play.svg"); + + /* mask-size: cover; */ + /* background-color: var(--audio-color-1); */ + height: 72px; + width: 72px; + /* height: 100%; */ + display: block; + /* transform: scale(60%); */ + /* background-color: #565656; */ +} + +#volume-on-btn { + background: url("/static/icn/volume-up.svg"); + height: 32px; + width: 32px; + display: block; +} + +#playback-rate-btn { + background: url("/static/icn/speed.svg"); + height: 48px; + width: 48px; + display: block; + position: relative; + font-family: inherit; +} + +#playback-rate-btn span { + position: absolute; + bottom: 0; + + left: 50%; + transform: translate(-50%, 0); + font-family: inherit; +} + +#rewind-btn { + background: url("/static/icn/rewind.svg"); + height: 28px; + width: 28px; +} + +#ff-btn { + background: url("/static/icn/ff.svg"); + height: 28px; + width: 28px; +} + +#bkm-save-btn { + background: url("/static/icn/bookmark-save.svg"); + height: 28px; + width: 28px; +} + +#bkm-delete-btn { + background: url("/static/icn/bookmark-delete.svg"); + height: 28px; + width: 28px; +} + +#bkm-prev-btn { + background: url("/static/icn/bookmark-prev.svg"); + height: 28px; + width: 28px; +} + +#bkm-next-btn { + background: url("/static/icn/bookmark-next.svg"); + height: 28px; + width: 28px; +} + +#play-btn, +#volume-on-btn, +#volume-off-btn, +#rewind-btn, +#ff-btn, +#playback-rate-btn, +#bkm-save-btn, +#bkm-delete-btn, +#bkm-prev-btn, +#bkm-next-btn { + background-position: center; + background-repeat: no-repeat; + background-size: cover; + border: none; + padding: 0; + border-radius: 50%; + + flex-shrink: 0; +} + +.volume::-moz-range-thumb { + background-position: center; + background-repeat: no-repeat; + background-size: cover; + border: none; + padding: 0; +} + +.volume::-webkit-slider-thumb { + background-position: center; + background-repeat: no-repeat; + background-size: cover; + border: none; + padding: 0; +} + +/* #play-btn { */ +/* width: 64px; */ +/* height: 64px; */ +/* /~ background-color: #3f3f3f; ~/ */ +/* border: 4px solid var(--audio-color-1); */ +/* background: none; */ +/* /~ filter: drop-shadow(0 0 0 rgba(0, 0, 0, 0.75)); ~/ */ +/* } */ +/* #play-btn svg { */ +/* stroke: #9de6d8; */ +/* stroke-width: 2.5; */ +/* transform: scale(70%); */ +/* } */ + +.timeline { + -webkit-appearance: none; + width: 100%; + height: 1.1rem; + margin: 0; + background-color: #fff; + border-radius: 5px; + background-size: 0% 100%; + background-image: linear-gradient(var(--audio-color-1), var(--audio-color-1)); + background-repeat: no-repeat; +} + +.volume { + -webkit-appearance: none; + width: 100%; + height: 0.6em; + margin: 0; + background-color: #fff; + border-radius: 5px; + background-size: 100% 100%; + background-image: linear-gradient(var(--audio-color-1), var(--audio-color-1)); + background-repeat: no-repeat; + /* margin-bottom: 1.1rem; */ +} + +.timeline::-webkit-slider-runnable-track, +.volume::-webkit-slider-runnable-track { + -webkit-appearance: none; + box-shadow: none; + border: none; + /* background: transparent; */ +} + +.timeline::-moz-range-track, +.volume::-moz-range-track { + box-shadow: none; + border: none; + /* background: transparent; */ +} + +.volume-container { + grid-column: 1/-1; + /* display: flex; */ + /* align-items: center; */ + /* flex: 0.2; */ +} + +.rewind-container { + display: grid; + grid-template-columns: 1fr min-content; + /* justify-content: space-between; */ + /* align-items: center; */ + /* width: max-content; */ + /* gap: 1.2rem; */ +} + +/* .rewind-btn-container { */ +/* display: flex; */ +/* gap: 0.3rem; */ +/* } */ + +#rewind-option { + border: none; + border-radius: 5px; + width: 90%; + height: 1.6rem; + padding: 0.2rem 0 0.2rem 0.8rem; + font-family: inherit; +} + +.audio-player-right-container { + display: grid; + grid-template-columns: 1fr 1fr; + /* padding: 0.7rem 0.7rem 0.7rem 0; */ + grid-template-columns: max-content max-content; + align-items: center; + justify-items: center; + row-gap: 0.6rem; + column-gap: 0.8rem; +} + +.duration-container { + display: flex; + justify-content: space-between; +} + +/* .timeline::-webkit-slider-thumb { */ +/* -webkit-appearance: none; */ +/* width: 1em; */ +/* height: 1em; */ +/* border-radius: 50%; */ +/* /~ cursor: pointer; ~/ */ +/* /~ opacity: 0; ~/ */ +/* /~ transition: all 0.1s; ~/ */ +/* background-color: #a94672; */ +/* } */ + +/* .timeline::-webkit-slider-thumb:hover { */ +/* background-color: #943f65; */ +/* } */ + +/* .timeline:hover::-webkit-slider-thumb { */ +/* opacity: 1; */ +/* } */ + +.timeline::-moz-range-thumb { + width: 1px; + height: 1em; + opacity: 0; +} + +.timeline::-webkit-slider-thumb { + -webkit-appearance: none; + width: 1px; + height: 1em; + opacity: 0; +} + +.volume::-moz-range-thumb { + width: 20px; + height: 20px; + background-image: url("/static/icn/volume-up.svg"); + border: 2px solid #89c2f9; + background-size: 80%; + border-radius: 5px; +} + +.volume::-webkit-slider-thumb { + -webkit-appearance: none; + width: 20px; + height: 20px; + background-image: url("/static/icn/volume-up.svg"); + border: 2px solid #89c2f9; + background-size: 80%; + border-radius: 5px; +} + +/* .timeline::-moz-range-thumb:hover { */ +/* background-color: #7cbefc; */ +/* } */ + +/* .timeline:hover::-moz-range-thumb { */ +/* opacity: 1; */ +/* } */ + +/* .marker { */ +/* /~ background-color: red; ~/ */ +/* height: 1rem; */ +/* position: absolute; */ +/* top: 0.1rem; */ +/* left: 3%; */ +/* /~ background: linear-gradient( ~/ */ +/* /~ to right, ~/ */ +/* /~ transparent 10%, ~/ */ +/* /~ #ff6464 10%, ~/ */ +/* /~ #ff6464 12%, ~/ */ +/* /~ transparent 12%, ~/ */ +/* /~ transparent 64%, ~/ */ +/* /~ green 64%, ~/ */ +/* /~ green 66%, ~/ */ +/* /~ transparent 66% ~/ */ +/* /~ ); ~/ */ +/* width: 2%; */ +/* user-select: none; */ +/* pointer-events: none; */ +/* } */ + +/* marker -> 27 */ + +/* transparent = 26 */ +/* marker start = 26 */ +/* marker end = 28 */ +/* transparent = 28 */ + +.bookmark-container { + display: grid; + grid-template-columns: 1fr 1fr; +} + +.bookmar-jump-container { + justify-self: end; +} diff --git a/lute/static/icn/bookmark-delete.svg b/lute/static/icn/bookmark-delete.svg new file mode 100644 index 00000000..0c1f9901 --- /dev/null +++ b/lute/static/icn/bookmark-delete.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/lute/static/icn/bookmark-next.svg b/lute/static/icn/bookmark-next.svg new file mode 100644 index 00000000..36dfc150 --- /dev/null +++ b/lute/static/icn/bookmark-next.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/lute/static/icn/bookmark-prev.svg b/lute/static/icn/bookmark-prev.svg new file mode 100644 index 00000000..4d04a37b --- /dev/null +++ b/lute/static/icn/bookmark-prev.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/lute/static/icn/bookmark-save.svg b/lute/static/icn/bookmark-save.svg new file mode 100644 index 00000000..4967e1ad --- /dev/null +++ b/lute/static/icn/bookmark-save.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/lute/static/icn/ff.svg b/lute/static/icn/ff.svg new file mode 100644 index 00000000..4b5552c7 --- /dev/null +++ b/lute/static/icn/ff.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/lute/static/icn/pause.svg b/lute/static/icn/pause.svg new file mode 100644 index 00000000..c457d0cd --- /dev/null +++ b/lute/static/icn/pause.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/lute/static/icn/play.svg b/lute/static/icn/play.svg new file mode 100644 index 00000000..4160cda4 --- /dev/null +++ b/lute/static/icn/play.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/lute/static/icn/rewind.svg b/lute/static/icn/rewind.svg new file mode 100644 index 00000000..811e6fe7 --- /dev/null +++ b/lute/static/icn/rewind.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/lute/static/icn/speed.svg b/lute/static/icn/speed.svg new file mode 100644 index 00000000..b0c3a5cc --- /dev/null +++ b/lute/static/icn/speed.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/lute/static/icn/stop.svg b/lute/static/icn/stop.svg new file mode 100644 index 00000000..ab3b09fc --- /dev/null +++ b/lute/static/icn/stop.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/lute/static/icn/volume-off.svg b/lute/static/icn/volume-off.svg new file mode 100644 index 00000000..d3d63d85 --- /dev/null +++ b/lute/static/icn/volume-off.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/lute/static/icn/volume-up.svg b/lute/static/icn/volume-up.svg new file mode 100644 index 00000000..ec30b21e --- /dev/null +++ b/lute/static/icn/volume-up.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lute/static/js/player.js b/lute/static/js/player.js new file mode 100644 index 00000000..5f831563 --- /dev/null +++ b/lute/static/js/player.js @@ -0,0 +1,280 @@ +const player = document.querySelector("#player"); +const timeline = document.querySelector(".timeline"); +const volumeLine = document.querySelector(".volume"); +const playBtn = document.querySelector("#play-btn"); +const playBtnIcon = document.querySelector("#play-btn span"); +const browseButton = document.querySelector("#myfile"); +const durationContainer = document.querySelector(".duration-container"); +const durationElement = document.querySelector(".duration-container .duration"); +const currentTimeElement = document.querySelector( + ".duration-container .current-time" +); +const rewindButton = document.querySelector("#rewind-btn"); +const ffButton = document.querySelector("#ff-btn"); +const playbackRateButton = document.querySelector("#playback-rate-btn"); +const playbackRateIndicator = document.querySelector("#playback-rate-btn span"); +const rewindAmountOption = document.querySelector("#rewind-option"); + +// const markerOverlay = document.querySelector(".marker"); +const timelineContainer = document.querySelector("#timeline-container"); +const bookmarkSaveBtn = document.querySelector("#bkm-save-btn"); +const bookmarkDeleteBtn = document.querySelector("#bkm-delete-btn"); +const bookmarkPrevBtn = document.querySelector("#bkm-prev-btn"); +const bookmarkNextBtn = document.querySelector("#bkm-next-btn"); + +const theTextItems = document.querySelectorAll("#thetext .textitem"); + +const bookmarksArray = []; +let lastPlayTime = null; +let activeBookmark = null; + +//let duration = 0; +let jumpTimeBy = Number(rewindAmountOption.value); + +player.onloadedmetadata = function () { + //console.log(player.duration); + durationElement.textContent = calculateTime(player.duration); + // durationContainer.style.display = "flex"; + //player.playbackRate = 1.0; + // console.log(lastPlayTime); + // if (lastPlayTime) player.currentTime = lastPlayTime; + if (lastPlayTime) timeline.value = lastPlayTime; + + playBtn.style.backgroundImage = 'url("/static/icn/play.svg")'; + changeVolume(); + resetPlaybackRate(); + // changeTimelinePosition(); +}; + +// function activateBookmark(pos) { +// const activeBookmarkMarker = document.createElement("div"); +// marker.classList.add("active-marker"); +// timelineContainer.appendChild(marker); +// activeBookmarkMarker.style.cssText = ` +// left: ${pos}%; +// width: 0; +// height: 0; +// border-left: 5px solid transparent; +// border-right: 5px solid transparent; +// border-top: 7px solid #555; +// position: absolute; +// top: -7px; +// transform: translate(-50%);`; +// } + +function addMarker(pos) { + const marker = document.createElement("div"); + marker.classList.add("marker"); + timelineContainer.appendChild(marker); + marker.style.cssText = ` + position: absolute; + left: ${pos}%; + height: 1rem; + top: 0; + width: 1%; + transform: translate(-50%, 0); + background-color: orangered; + box-sizing: border-box; + user-select: none; + pointer-events: none; + `; +} + +// function getAudioName() { +// let audioPath = document.getElementById("#myfile").value; +// console.log(audioPath); +// if (audioPath) { +// let startIndex = +// audioPath.indexOf("\\") >= 0 +// ? audioPath.lastIndexOf("\\") +// : audioPath.lastIndexOf("/"); +// let filename = audioPath.substring(startIndex); +// if (filename.indexOf("\\") === 0 || filename.indexOf("/") === 0) { +// filename = filename.substring(1); +// } +// } +// } + +// browseButton.addEventListener("input", function () { +// const audioFile = document.getElementById("#myfile").files[0]; +// player.src = URL.createObjectURL(audioFile); +// }); + +function calculateTime(secs) { + const minutes = Math.floor(secs / 60); + const seconds = Math.floor(secs % 60); + const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`; + + return `${minutes}:${returnedSeconds}`; +} + +function disableScroll() { + scrollTop = document.documentElement.scrollTop; + scrollLeft = document.documentElement.scrollLeft; + + window.onscroll = function () { + window.scrollTo(scrollLeft, scrollTop); + }; +} + +function enableScroll() { + window.onscroll = function () {}; +} + +function resetPlaybackRate() { + player.playbackRate = 1.0; + playbackRateIndicator.textContent = "1.0"; +} + +function changeVolume() { + player.volume = volumeLine.value / 100; + volumeLine.style.backgroundSize = `${volumeLine.value}% 100%`; +} + +function updateCurrentTime() { + // console.log(player.duration); + if (player.duration) { + player.currentTime = (timeline.value / 100) * player.duration; + } +} + +function changeTimelinePosition() { + // const timelinePosition = (player.currentTime / player.duration) * 100; + timelinePositionPercent = convertTimeToPercentage(); + timeline.style.backgroundSize = `${timelinePositionPercent}% 100%`; + timeline.value = timelinePositionPercent; + currentTimeElement.textContent = calculateTime(player.currentTime); + + lastPlayTime = Number(Number(timeline.value).toPrecision(3)); + // console.log(lastPlayTime); +} + +function convertTimeToPercentage() { + return (player.currentTime / player.duration) * 100; +} + +rewindAmountOption.addEventListener("change", function () { + jumpTimeBy = Number(rewindAmountOption.value); +}); + +browseButton.addEventListener("change", function (e) { + if (e.target.files[0]) { + // player.setAttribute("src", `/static/${e.target.files[0].name}`); + // const audioFile = document.getElementById("#myfile").files[0]; + player.src = URL.createObjectURL(e.target.files[0]); + } +}); + +playBtn.addEventListener("click", function (e) { + if (player.paused) { + player.play(); + // playBtn.style.backgroundImage = 'url("/static/icn/pause.svg")'; + } else { + player.pause(); + // playBtn.style.backgroundImage = 'url("/static/icn/play.svg")'; + } +}); + +player.addEventListener("pause", function () { + playBtn.style.backgroundImage = 'url("/static/icn/play.svg")'; +}); + +player.addEventListener("play", function () { + playBtn.style.backgroundImage = 'url("/static/icn/pause.svg")'; +}); + +ffButton.addEventListener("click", function () { + player.currentTime = player.currentTime + jumpTimeBy; +}); + +rewindButton.addEventListener("click", function () { + player.currentTime = player.currentTime - jumpTimeBy; +}); + +playbackRateButton.addEventListener("wheel", function (e) { + if (e.deltaY < 0) player.playbackRate += 0.1; + else player.playbackRate -= 0.1; + + playbackRateIndicator.textContent = player.playbackRate.toFixed(1); +}); + +theTextItems.forEach((item) => + item.addEventListener("mousedown", () => player.pause()) +); + +playbackRateButton.addEventListener("mouseover", disableScroll); +playbackRateButton.addEventListener("mouseleave", enableScroll); +playbackRateButton.addEventListener("click", resetPlaybackRate); +player.addEventListener("timeupdate", changeTimelinePosition); +timeline.addEventListener("input", updateCurrentTime); +volumeLine.addEventListener("input", changeVolume); + +bookmarkSaveBtn.addEventListener("click", function () { + const markerPos = Number(convertTimeToPercentage().toPrecision(3)); + addMarker(markerPos); + // activateBookmark(markerPos); + activeBookmark = markerPos; + bookmarksArray.push(markerPos); + bookmarksArray.sort(function (a, b) { + return a - b; + }); + + console.log(bookmarksArray); +}); + +// function jumpToBookmark(oper) { +// if (activeBookmark) { +// let ind; + +// if (oper === "prev") ind = bookmarksArray.indexOf(activeBookmark) - 1; +// else ind = bookmarksArray.indexOf(activeBookmark) + 1; + +// const m = bookmarksArray[ind]; +// activeBookmark = m; +// timeline.value = m; +// updateCurrentTime(); +// // console.log(m); +// // console.log(calculateTime(player.currentTime)); +// } +// } + +bookmarkPrevBtn.addEventListener("click", function () { + jumpToBookmark("prev"); +}); +bookmarkNextBtn.addEventListener("click", function () { + jumpToBookmark("next"); +}); + +function jumpToBookmark(oper) { + if (lastPlayTime) { + let ind; + + // console.log(`lastPlayTime initially is ${lastPlayTime}`); + + const firstBiggerInd = bookmarksArray.findIndex( + (element) => element > lastPlayTime + ); + + // console.log(`firstBiggerInd is ${bookmarksArray[firstBiggerInd]}`); + + if (oper === "next") { + if (firstBiggerInd == -1) return; + else ind = firstBiggerInd; + } else { + if (firstBiggerInd == -1) ind = bookmarksArray.length - 1; + else ind = firstBiggerInd - 1; + + if (ind == 0) return; + else if (bookmarksArray[ind] == lastPlayTime) ind = ind - 1; + } + + const m = bookmarksArray[ind]; + activeBookmark = m; + timeline.value = m; + lastPlayTime = m; + updateCurrentTime(); + // console.log(`m is ${m}`); + // console.log(`lastPlayTime after is ${lastPlayTime}`); + // console.log(calculateTime(player.currentTime)); + } +} diff --git a/lute/templates/base.html b/lute/templates/base.html index 0eae4744..7ac349ae 100644 --- a/lute/templates/base.html +++ b/lute/templates/base.html @@ -22,10 +22,12 @@ + + @@ -33,6 +35,9 @@ + + + @@ -108,7 +113,6 @@

About diff --git a/lute/templates/index.html b/lute/templates/index.html index 183e2ae5..86c44f78 100644 --- a/lute/templates/index.html +++ b/lute/templates/index.html @@ -1,36 +1,35 @@ -{% extends "base.html" %} - -{% block title %}Lute index{% endblock %} - -{# Must pass empty block to base, or an empty h1 is written. #} -{% block header %}{% endblock %} - -{% block body %} - -{% if tutorial_book_id %} +{% extends "base.html" %} {% block title %}Lute index{% endblock %} {# Must pass +empty block to base, or an empty h1 is written. #} {% block header %}{% endblock +%} {% block body %} {% if tutorial_book_id %}
-

The Lute database has been loaded with a - brief tutorial, - and some languages and short texts for you to try out. +

+ The Lute database has been loaded with a + brief tutorial, and some languages and short texts for you to try out. +

+

+ When you're done trying out the demo, + click here + to clear out the database. Note: this removes everything in the db.

-

When you're done trying out the demo, click here to clear out the - database. Note: this removes everything in the db.

-{% endif %} - -{% if is_production_data and backup_show_warning %} +{% endif %} {% if is_production_data and backup_show_warning %}
-

Warning: {{ backup_warning_msg }} Create a backup.

+

+ Warning: {{ backup_warning_msg }} + Create a backup. +

{% endif %}
{% if not have_languages %} -

To get started using Lute, first create your language.

-{% else %} - {% include "book/tablelisting.html" %} -{% endif %} - -{% endblock %} +

+ To get started using Lute, first + create your language. +

+{% else %} {% include "book/tablelisting.html" %} {% endif %} {% endblock %} diff --git a/lute/templates/read/index.html b/lute/templates/read/index.html index a35aced4..b6ea8187 100644 --- a/lute/templates/read/index.html +++ b/lute/templates/read/index.html @@ -1,18 +1,21 @@ -{% extends 'base.html' %} +{% extends 'base.html' %} {% block title %}Reading "{{ html_title +}}"{% endblock %} {% block body %} -{% block title %}Reading "{{ html_title }}"{% endblock %} - -{% block body %} - - +
@@ -20,76 +23,156 @@
-
- + Home {% if config.ENV == 'dev' %} - Dev environment + Dev environment {% endif %}
-

+

{% if prev10page != pagenum %} - « + « {% else %} - « - {% endif %} - - {% if prevpage != pagenum %} - + « + {% endif %} {% if prevpage != pagenum %} + {% else %} - - {% endif %} - - {{ pagenum }}/{{ pagecount }} - - {% if pagenum != pagecount %} - + + {% endif %} {{ pagenum }}/{{ pagecount }} {% if pagenum != pagecount + %} + {% else %} - - {% endif %} - - {% if next10page != pagecount %} - » + + {% endif %} {% if next10page != pagecount %} + » {% else %} - » + » {% endif %}

{% if book.source_uri %} + + + - + {% endif %} - Edit + Edit - +

+ + {% if pagenum == 1 %} +

{{ book.title }}

+
+ + +
+
+ +
+
+
+ + +
+ 0:00 + 0:00 +
+
+ +
+
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+
- {% if pagenum == 1 %} -

{{ book.title }}

{% endif %} - - + + {# Hack for js translation keyboard shortcut. #} - + -
+
{% include 'read/sentences.html' %}
- -
- - - + + +
{% endblock %}