diff --git a/web/server/handlers.go b/web/server/handlers.go
index 1ecc674..8015ea0 100644
--- a/web/server/handlers.go
+++ b/web/server/handlers.go
@@ -9,8 +9,17 @@ import (
func root(c *gin.Context) {
authorized := c.GetBool("authorized")
if authorized {
- c.HTML(http.StatusOK, "quotes.html", nil)
+ c.Redirect(http.StatusSeeOther, "/quotes")
} else {
c.HTML(http.StatusOK, "auth.html", nil)
}
}
+
+func quotes(c *gin.Context) {
+ authorized := c.GetBool("authorized")
+ if authorized {
+ c.HTML(http.StatusOK, "quotes.html", nil)
+ } else {
+ c.Redirect(http.StatusSeeOther, "/")
+ }
+}
diff --git a/web/server/server.go b/web/server/server.go
index 712058a..c2836b4 100644
--- a/web/server/server.go
+++ b/web/server/server.go
@@ -20,6 +20,7 @@ func Serve(addr string) {
r.Static("/static", "./static")
r.GET("/", api.MiddlewareAuth, root)
+ r.GET("/quotes", api.MiddlewareAuth, quotes)
r.Run(addr)
}
diff --git a/web/static/css/skazanull.css b/web/static/css/skazanull.css
new file mode 100644
index 0000000..a8b5116
--- /dev/null
+++ b/web/static/css/skazanull.css
@@ -0,0 +1,5 @@
+.loader {
+ display: block;
+ margin: 0 auto;
+ max-width: 20%;
+}
diff --git a/web/static/images/loader.gif b/web/static/images/loader.gif
new file mode 100644
index 0000000..d15dcdb
Binary files /dev/null and b/web/static/images/loader.gif differ
diff --git a/web/static/js/quotes.js b/web/static/js/quotes.js
new file mode 100644
index 0000000..d0b677f
--- /dev/null
+++ b/web/static/js/quotes.js
@@ -0,0 +1,161 @@
+const PAGE_SIZE = 10;
+var totalPages;
+var currPage = +sessionStorage.getItem("page");
+if (currPage == 0) {
+ currPage = 1;
+}
+var search = sessionStorage.getItem("search");
+if (search == null) {
+ search = "";
+}
+var sorting = sessionStorage.getItem("sort");
+if (sorting == null) {
+ sorting = "-datetime";
+}
+
+function escapedString(str) {
+ return str
+ .replace("&", "&")
+ .replace("<", "<")
+ .replace(">", ">")
+ .replace("\n", "
");
+}
+
+function renderBlockQuote(quote) {
+ return `
+
+
+
+
${escapedString(quote.text)}
+
${escapedString(quote.author)}
+
${quote.datetime}
+
+
+
+
+
+
+
+ `;
+}
+
+function load() {
+ var quotesCount;
+ failed = false;
+ $.ajax({
+ async: false,
+ url: "/api/quotes/count",
+ type: "GET",
+ dataType: "json",
+ success: function (resp) {
+ quotesCount = resp.count;
+ },
+ error: function (err) {
+ $("#error-message").text(err.responseJSON.error);
+ $("#error").removeClass("hidden");
+ failed = true;
+ $("#block-quotes-loader").addClass("hidden");
+ },
+ });
+ if (failed) {
+ return;
+ }
+ totalPages = Math.ceil(quotesCount / PAGE_SIZE);
+ $("#input-search").val(search);
+ $("#input-sorting").val(sorting);
+ $("#btn-page-curr").text(currPage);
+ if (currPage > 1) {
+ $("#btn-page-first").removeClass("hidden");
+ if (currPage > 2) {
+ $("#btn-page-prev").text(currPage - 1);
+ $("#btn-page-prev").removeClass("hidden");
+ if (currPage > 3) {
+ $("#pages-prev").removeClass("hidden");
+ }
+ }
+ }
+ if (currPage < totalPages) {
+ $("#btn-page-last").text(totalPages);
+ $("#btn-page-last").removeClass("hidden");
+ if (currPage < totalPages - 1) {
+ $("#btn-page-next").text(currPage + 1);
+ $("#btn-page-next").removeClass("hidden");
+ if (currPage < totalPages - 2) {
+ $("#pages-next").removeClass("hidden");
+ }
+ }
+ }
+ container = $("#block-quotes");
+ $.ajax({
+ url: `/api/quotes?filter=${encodeURIComponent(search)}&sort=${encodeURIComponent(sorting)}&limit=${PAGE_SIZE}&offset=${(currPage - 1)*PAGE_SIZE}`,
+ type: "GET",
+ dataType: "json",
+ success: function (resp) {
+ resp.forEach((quote) => {
+ container.append(renderBlockQuote(quote));
+ });
+ },
+ error: function (err) {
+ $("#error-message").text(err.responseJSON.error);
+ $("#error").removeClass("hidden");
+ },
+ complete: function () {
+ $("#block-quotes-loader").addClass("hidden");
+ },
+ });
+}
+
+function reload() {
+ container = $("#block-quotes");
+ loader = $("#block-quotes-loader");
+ loader.removeClass("hidden");
+ container.html(loader);
+ $("#error").addClass("hidden");
+ $("#btn-page-first").addClass("hidden");
+ $("#pages-prev").addClass("hidden");
+ $("#btn-page-prev").addClass("hidden");
+ $("#btn-page-next").addClass("hidden");
+ $("#pages-next").addClass("hidden");
+ $("#btn-page-last").addClass("hidden");
+ load();
+}
+
+$(window).on("load", function (e) {
+ load();
+});
+
+$(document).on("click", "#btn-refresh", function (e) {
+ search = $("#input-search").val();
+ sorting = $("#input-sorting option:selected").val();
+ reload();
+ sessionStorage.setItem("search", search);
+ sessionStorage.setItem("sort", sorting);
+});
+
+$(document).on("click", "#btn-page-first", function (e) {
+ currPage = 1;
+ reload();
+ sessionStorage.setItem("page", currPage);
+});
+
+$(document).on("click", "#btn-page-prev", function (e) {
+ currPage--;
+ reload();
+ sessionStorage.setItem("page", currPage);
+});
+
+$(document).on("click", "#btn-page-next", function (e) {
+ currPage++;
+ reload();
+ sessionStorage.setItem("page", currPage);
+});
+
+$(document).on("click", "#btn-page-last", function (e) {
+ currPage = totalPages;
+ reload();
+ sessionStorage.setItem("page", currPage);
+});
diff --git a/web/templates/head.html b/web/templates/head.html
index f023714..5c86c5d 100644
--- a/web/templates/head.html
+++ b/web/templates/head.html
@@ -4,6 +4,7 @@
+
diff --git a/web/templates/quotes.html b/web/templates/quotes.html
new file mode 100644
index 0000000..ffb0d8b
--- /dev/null
+++ b/web/templates/quotes.html
@@ -0,0 +1,62 @@
+
+
+
+
+ {{ template "head" . }}
+ Цитаты | SkazaNull
+
+
+
+
+
+
+
Пацанские цитаты
+
Читайте и угорайте :)
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
...
+
+
+
+
...
+
+
+
+
+
+ © Masahiko AMANO (H1K0), 2025—present
+
+
+
+
+
+
+
+