favorites_view.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. const { form, button, div, h2, p, section, input, a, span, img } = require("../server/node_modules/hyperaxe");
  2. const { template, i18n, userLink} = require("./main_views");
  3. const moment = require("../server/node_modules/moment");
  4. const { renderUrl } = require("../backend/renderUrl");
  5. const safeArr = (v) => (Array.isArray(v) ? v : []);
  6. const safeText = (v) => String(v || "").trim();
  7. const buildReturnTo = (filter) => {
  8. const f = safeText(filter || "all");
  9. return `/favorites?filter=${encodeURIComponent(f)}`;
  10. };
  11. const renderTags = (tags) => {
  12. const list = safeArr(tags).map((t) => String(t || "").trim()).filter(Boolean);
  13. return list.length
  14. ? div(
  15. { class: "card-tags" },
  16. list.map((tag) => a({ href: `/search?query=%23${encodeURIComponent(tag)}`, class: "tag-link" }, `#${tag}`))
  17. )
  18. : null;
  19. };
  20. const renderBookmarkUrl = (item) => {
  21. if (item.kind !== "bookmarks") return null;
  22. if (!item.url) return null;
  23. return p(
  24. a(
  25. { href: item.url, target: "_blank", rel: "noreferrer noopener", class: "bookmark-url" },
  26. item.url
  27. )
  28. );
  29. };
  30. const renderImagePreview = (item) => {
  31. if (item.kind !== "images") return null;
  32. if (!item.url) return null;
  33. return div(
  34. { class: "image-container" },
  35. a(
  36. { href: item.viewHref },
  37. img({
  38. src: `/image/256/${encodeURIComponent(item.url)}`,
  39. alt: item.title || "",
  40. class: "media-preview",
  41. loading: "lazy"
  42. })
  43. )
  44. );
  45. };
  46. const renderFavoriteCard = (item, filter) => {
  47. const returnTo = buildReturnTo(filter);
  48. const titlePrefix = `[${String(item.kind || "").toUpperCase()}]`;
  49. const title = safeText(item.title) || safeText(item.name) || safeText(item.category) || safeText(item.url) || "";
  50. const ts = item.updatedAt || item.createdAt;
  51. const absDate = ts ? moment(ts).format("YYYY/MM/DD HH:mm:ss") : "";
  52. return div(
  53. { class: "tags-header bookmark-card" },
  54. div(
  55. { class: "bookmark-topbar" },
  56. div(
  57. { class: "bookmark-topbar-left" },
  58. form(
  59. { method: "GET", action: item.viewHref },
  60. input({ type: "hidden", name: "returnTo", value: returnTo }),
  61. button({ type: "submit", class: "filter-btn" }, i18n.viewDetails)
  62. ),
  63. form(
  64. {
  65. method: "POST",
  66. action: `/favorites/remove/${encodeURIComponent(item.kind)}/${encodeURIComponent(item.favId)}`,
  67. class: "bookmark-favorite-form"
  68. },
  69. input({ type: "hidden", name: "returnTo", value: returnTo }),
  70. button({ type: "submit", class: "filter-btn" }, i18n.favoritesRemoveButton)
  71. )
  72. )
  73. ),
  74. title ? h2(`${titlePrefix} ${title}`) : h2(titlePrefix),
  75. renderImagePreview(item),
  76. renderBookmarkUrl(item),
  77. safeText(item.description) ? p(...renderUrl(item.description)) : null,
  78. renderTags(item.tags),
  79. p(
  80. { class: "card-footer" },
  81. absDate ? span({ class: "date-link" }, `${absDate} ${i18n.performed} `) : "",
  82. item.author ? userLink(item.author) : ""
  83. )
  84. );
  85. };
  86. exports.favoritesView = async (items, filter = "all", counts = {}) => {
  87. const c = counts || {};
  88. const total = typeof c.all === "number" ? c.all : safeArr(items).length;
  89. return template(
  90. i18n.favoritesTitle,
  91. section(
  92. div({ class: "tags-header" }, h2(i18n.favoritesTitle), p(i18n.favoritesDescription)),
  93. div(
  94. { class: "filters" },
  95. form(
  96. { method: "GET", action: "/favorites", class: "ui-toolbar ui-toolbar--filters" },
  97. button(
  98. { type: "submit", name: "filter", value: "all", class: filter === "all" ? "filter-btn active" : "filter-btn" },
  99. `${i18n.favoritesFilterAll} (${total})`
  100. ),
  101. button(
  102. { type: "submit", name: "filter", value: "recent", class: filter === "recent" ? "filter-btn active" : "filter-btn" },
  103. `${i18n.favoritesFilterRecent} (${total})`
  104. ),
  105. button(
  106. { type: "submit", name: "filter", value: "audios", class: filter === "audios" ? "filter-btn active" : "filter-btn" },
  107. `${i18n.favoritesFilterAudios} (${c.audios || 0})`
  108. ),
  109. button(
  110. { type: "submit", name: "filter", value: "bookmarks", class: filter === "bookmarks" ? "filter-btn active" : "filter-btn" },
  111. `${i18n.favoritesFilterBookmarks} (${c.bookmarks || 0})`
  112. ),
  113. button(
  114. { type: "submit", name: "filter", value: "documents", class: filter === "documents" ? "filter-btn active" : "filter-btn" },
  115. `${i18n.favoritesFilterDocuments} (${c.documents || 0})`
  116. ),
  117. button(
  118. { type: "submit", name: "filter", value: "images", class: filter === "images" ? "filter-btn active" : "filter-btn" },
  119. `${i18n.favoritesFilterImages} (${c.images || 0})`
  120. ),
  121. button(
  122. { type: "submit", name: "filter", value: "maps", class: filter === "maps" ? "filter-btn active" : "filter-btn" },
  123. `${i18n.favoritesFilterMaps} (${c.maps || 0})`
  124. ),
  125. button(
  126. { type: "submit", name: "filter", value: "pads", class: filter === "pads" ? "filter-btn active" : "filter-btn" },
  127. `${i18n.favoritesFilterPads || "PADS"} (${c.pads || 0})`
  128. ),
  129. button(
  130. { type: "submit", name: "filter", value: "chats", class: filter === "chats" ? "filter-btn active" : "filter-btn" },
  131. `${i18n.favoritesFilterChats || "CHATS"} (${c.chats || 0})`
  132. ),
  133. button(
  134. { type: "submit", name: "filter", value: "calendars", class: filter === "calendars" ? "filter-btn active" : "filter-btn" },
  135. `${i18n.favoritesFilterCalendars || "CALENDARS"} (${c.calendars || 0})`
  136. ),
  137. button(
  138. { type: "submit", name: "filter", value: "videos", class: filter === "videos" ? "filter-btn active" : "filter-btn" },
  139. `${i18n.favoritesFilterVideos} (${c.videos || 0})`
  140. ),
  141. button(
  142. { type: "submit", name: "filter", value: "torrents", class: filter === "torrents" ? "filter-btn active" : "filter-btn" },
  143. `${i18n.favoritesFilterTorrents || "TORRENTS"} (${c.torrents || 0})`
  144. )
  145. )
  146. ),
  147. div({ class: "bookmark-list" }, safeArr(items).length ? safeArr(items).map((it) => renderFavoriteCard(it, filter)) : p(i18n.favoritesNoItems))
  148. )
  149. );
  150. };