From b1e6f250e1c9d69f80899e4b877f40ccf8a214df Mon Sep 17 00:00:00 2001 From: Killy Date: Wed, 27 Dec 2017 16:15:57 +0300 Subject: www: responsive layout (2) --- .../java/com/juick/www/controllers/Messages.java | 95 +++++--- juick-www/src/main/resources/messages.properties | 1 + .../src/main/resources/messages_ru.properties | 1 + juick-www/src/main/static/scripts.js | 19 +- juick-www/src/main/static/style.css | 266 ++++++++++----------- juick-www/src/main/webapp/WEB-INF/views/index.html | 2 - .../webapp/WEB-INF/views/partial/homecolumn.html | 38 ++- .../webapp/WEB-INF/views/partial/navigation.html | 79 +++--- .../webapp/WEB-INF/views/partial/tagcolumn.html | 8 + .../webapp/WEB-INF/views/partial/usercolumn.html | 49 ++-- 10 files changed, 314 insertions(+), 244 deletions(-) diff --git a/juick-www/src/main/java/com/juick/www/controllers/Messages.java b/juick-www/src/main/java/com/juick/www/controllers/Messages.java index 2af6c21a..381faf34 100644 --- a/juick-www/src/main/java/com/juick/www/controllers/Messages.java +++ b/juick-www/src/main/java/com/juick/www/controllers/Messages.java @@ -18,12 +18,14 @@ package com.juick.www.controllers; import com.juick.Tag; import com.juick.formatters.PlainTextFormatter; +import com.juick.server.helpers.TagStats; import com.juick.server.util.HttpForbiddenException; import com.juick.server.util.HttpNotFoundException; import com.juick.server.util.UserUtils; import com.juick.server.util.WebUtils; import com.juick.service.*; import com.juick.www.Utils; +import com.mitchellbosecke.pebble.extension.i18n.UTF8Control; import org.apache.commons.codec.CharEncoding; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; @@ -42,7 +44,10 @@ import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URLEncoder; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; import java.util.function.BooleanSupplier; import java.util.stream.Collectors; @@ -59,6 +64,8 @@ public class Messages { @Inject private MessagesService messagesService; @Inject + private SubscriptionService subscriptionService; + @Inject private Sape sape; @Inject private PMQueriesService pmQueriesService; @@ -75,9 +82,17 @@ public class Messages { model.addAttribute("statsMyBL", userService.getUserBLUsers(user.getUid()).size()); model.addAttribute("statsMessages", userService.getStatsMessages(user.getUid())); model.addAttribute("statsReplies", userService.getStatsReplies(user.getUid())); + model.addAttribute("statsPhotos", userService.getStatsPhotos(user.getUid())); + model.addAttribute("statsFavorites", userService.getStatsFavorites(user.getUid())); model.addAttribute("iread", userService.getUserReadLeastPopular(user.getUid(), 8)); - model.addAttribute("tagStats", tagService.getUserTagStats(user.getUid()) - .stream().sorted((e1, e2) -> Integer.compare(e2.getUsageCount(), e1.getUsageCount())).limit(20).map(t -> t.getTag().getName()).collect(Collectors.toList())); + model.addAttribute("tagStats", + tagService.getUserTagStats(user.getUid()) + .stream() + .sorted(Comparator.comparing(TagStats::getUsageCount).reversed()) + .limit(20) + .map(t -> t.getTag().getName()) + .collect(Collectors.toList()) + ); } @GetMapping("/{anything}/**") @@ -118,76 +133,82 @@ public class Messages { @RequestParam(name = "search", required = false) String paramSearch, @RequestParam(name = "before", required = false, defaultValue = "0") Integer paramBefore, @CookieValue(name = "sape_cookie", required = false, defaultValue = StringUtils.EMPTY) String sapeCookie, - ModelMap model) throws IOException { + ModelMap model, + Locale locale) throws IOException { if (tag != null) { return "redirect:/tag/" + URLEncoder.encode(tag, CharEncoding.UTF_8); } - com.juick.User visitor = UserUtils.getCurrentUser(); - if (paramSearch != null && paramSearch.length() > 64) { paramSearch = null; } + ResourceBundle messagesBundle = ResourceBundle.getBundle("messages", locale, new UTF8Control()); + com.juick.User visitor = UserUtils.getCurrentUser(); + String title; List mids; - if (paramSearch != null) { - title = "Поиск: " + StringEscapeUtils.escapeHtml4(paramSearch); + title = messagesBundle.getString("label.search") + ": " + + StringEscapeUtils.escapeHtml4(paramSearch); mids = messagesService.getSearch(Utils.encodeSphinx(paramSearch), paramBefore); } else if (paramShow == null) { if (visitor.getUid() > 0) { - title = "Популярные"; + title = messagesBundle.getString("title.index.user"); mids = messagesService.getPopular(visitor.getUid(), paramBefore); } else { - title = "Микроблоги Juick: популярные записи"; + title = messagesBundle.getString("title.index.anonym"); mids = messagesService.getPopular(0, paramBefore); } - } else if (paramShow.equals("top")) { return "redirect:/"; } else if (paramShow.equals("my") && !visitor.isAnonymous()) { - title = "Моя лента"; + title = messagesBundle.getString("link.my"); mids = messagesService.getMyFeed(visitor.getUid(), paramBefore, true); } else if (paramShow.equals("private") && !visitor.isAnonymous()) { - title = "Приватные"; + title = messagesBundle.getString("link.privateMessages"); mids = messagesService.getPrivate(visitor.getUid(), paramBefore); } else if (paramShow.equals("discuss") && !visitor.isAnonymous()) { - title = "Обсуждения"; + title = messagesBundle.getString("link.discuss"); mids = messagesService.getDiscussions(visitor.getUid(), paramBefore); } else if (paramShow.equals("recommended") && !visitor.isAnonymous()) { - title = "Рекомендации"; + title = messagesBundle.getString("link.recommended"); mids = messagesService.getRecommended(visitor.getUid(), paramBefore); } else if (paramShow.equals("photos")) { - title = "Фотографии"; + title = messagesBundle.getString("link.withPhotos"); mids = messagesService.getPhotos(visitor.getUid(), paramBefore); } else if (paramShow.equals("all")) { - title = "Все сообщения"; + title = messagesBundle.getString("link.allMessages"); mids = messagesService.getAll(visitor.getUid(), paramBefore); } else { throw new HttpNotFoundException(); } + List msgs = messagesService.getMessages(mids); + if (visitor.getUid() != 0) { + List blUIDs = userService.checkBL( + visitor.getUid(), + msgs.stream().map(m -> m.getUser().getUid()).collect(Collectors.toList()) + ); + msgs.forEach(m -> m.ReadOnly |= blUIDs.contains(m.getUser().getUid())); + fillUserModel(model, visitor, visitor); + } + String head = StringUtils.EMPTY; if (paramBefore > 0 || paramShow != null) { head = ""; } + model.addAttribute("paramShow", !StringUtils.isEmpty(paramShow) + ? paramShow + : ((paramSearch != null) ? "search" : "top")); model.addAttribute("title", title); model.addAttribute("headers", head); model.addAttribute("visitor", visitor); model.addAttribute("noindex", !(paramShow == null && paramBefore == 0)); - List msgs = messagesService.getMessages(mids); - - if (visitor.getUid() != 0) { - fillUserModel(model, visitor, visitor); - List blUIDs = userService.checkBL(visitor.getUid(), - msgs.stream().map(m -> m.getUser().getUid()).collect(Collectors.toList())); - msgs.forEach(m -> m.ReadOnly |= blUIDs.contains(m.getUser().getUid())); - } model.addAttribute("msgs", msgs); - model.addAttribute("tags", tagService.getPopularTags()); - model.addAttribute("headers", head); - model.addAttribute("showAdv", - paramShow == null && paramBefore == 0 && paramSearch == null && visitor.getUid() == 0); + model.addAttribute("tags", (visitor.getUid() != 0) + ? subscriptionService.getSubscribedTags(visitor) + : tagService.getPopularTags()); + model.addAttribute("showAdv", paramShow == null && paramBefore == 0 && paramSearch == null && visitor.getUid() == 0); if (mids.size() >= 20) { String nextpage = "?before=" + mids.get(mids.size() - 1); if (paramShow != null) { @@ -370,21 +391,21 @@ public class Messages { return "views/users"; } - @GetMapping("/{uname}/bl") - protected String doGetBL(@PathVariable String uname, ModelMap model) throws IOException { - com.juick.User user = userService.getUserByName(uname); + @GetMapping("/bl") + protected String doGetBL(ModelMap model) throws IOException { com.juick.User visitor = UserUtils.getCurrentUser(); - if (visitor.isBanned() || visitor.getUid() != user.getUid()) { + if (visitor.isBanned()) { throw new HttpForbiddenException(); } - model.addAttribute("title", "Черный список " + user.getName()); + model.addAttribute("title", "Черный список " + visitor.getName()); model.addAttribute("headers", ""); model.addAttribute("visitor", visitor); - fillUserModel(model, user, visitor); - model.addAttribute("users", userService.getUserBLUsers(user.getUid())); + fillUserModel(model, visitor, visitor); + model.addAttribute("users", userService.getUserBLUsers(visitor.getUid())); return "views/users"; } + @GetMapping("/tag/{tagName}") protected String tagAction(HttpServletRequest request, @PathVariable String tagName, @@ -413,8 +434,6 @@ public class Messages { int visitor_uid = visitor.getUid(); - String title = "*" + StringEscapeUtils.escapeHtml4(paramTag.getName()); - model.addAttribute("title", title); List mids = messagesService.getTag(paramTag.TID, visitor_uid, before, (visitor_uid == 0) ? 40 : 20); List msgs = messagesService.getMessages(mids); if (visitor.getUid() != 0) { @@ -435,7 +454,7 @@ public class Messages { model.addAttribute("headers", head); model.addAttribute("visitor", visitor); model.addAttribute("tag", paramTag); - model.addAttribute("title", title); + model.addAttribute("title", "*" + StringEscapeUtils.escapeHtml4(paramTag.getName())); model.addAttribute("msgs", msgs); model.addAttribute("tags", tagService.getPopularTags()); model.addAttribute("noindex", before > 0); diff --git a/juick-www/src/main/resources/messages.properties b/juick-www/src/main/resources/messages.properties index 8bf51837..8e95321e 100644 --- a/juick-www/src/main/resources/messages.properties +++ b/juick-www/src/main/resources/messages.properties @@ -24,6 +24,7 @@ link.settings.about=About label.sponsor=Sponsor label.sponsors=Sponsors label.search=Search +label.searchInUserPosts=Search in {0} posts label.register=Register label.username=User name label.password=Password diff --git a/juick-www/src/main/resources/messages_ru.properties b/juick-www/src/main/resources/messages_ru.properties index 7c948bc5..637951ef 100644 --- a/juick-www/src/main/resources/messages_ru.properties +++ b/juick-www/src/main/resources/messages_ru.properties @@ -24,6 +24,7 @@ link.settings.about=О пользователе label.sponsor=Спонсор label.sponsors=Спонсоры label.search=Поиск +label.searchInUserPosts=Поиск в постах {0} label.register=Зарегистрироваться label.username=Имя пользователя label.password=Пароль diff --git a/juick-www/src/main/static/scripts.js b/juick-www/src/main/static/scripts.js index 6a28d96d..a3bff879 100644 --- a/juick-www/src/main/static/scripts.js +++ b/juick-www/src/main/static/scripts.js @@ -1,16 +1,8 @@ require('whatwg-fetch'); require('element-closest'); require('classlist.js'); -let killy = require('killy'); let Awesomplete = require('awesomplete'); - -if (!('remove' in Element.prototype)) { // Firefox <23 - Element.prototype.remove = function() { - if (this.parentNode) { - this.parentNode.removeChild(this); - } - }; -} +let killy = require('killy'); NodeList.prototype.forEach = Array.prototype.forEach; HTMLCollection.prototype.forEach = Array.prototype.forEach; @@ -691,10 +683,11 @@ ready(function () { }); }); - makeMenu( - document.querySelector('#user-menu'), - document.querySelector('#user-menu-dropdown') - ); + let userMenu = document.querySelector('#user-menu'); + let userMenuDropDown = document.querySelector('#user-menu-dropdown'); + if (userMenu) { + makeMenu(userMenu, userMenuDropDown); + } let column = document.querySelector('#column'); if (column && column.querySelector('#ctitle') && column.querySelector('#column-expander')) { diff --git a/juick-www/src/main/static/style.css b/juick-www/src/main/static/style.css index 2320b6e3..05175d7a 100644 --- a/juick-www/src/main/static/style.css +++ b/juick-www/src/main/static/style.css @@ -149,6 +149,7 @@ body > header { align-items: center; flex-direction: column; margin: 55px auto 0 auto; + padding: 0 8px; } body > header { margin-bottom: 15px; @@ -164,7 +165,7 @@ body > header { } #content { max-width: 100%; - padding: 0 8px; + /* padding: 0 8px; */ width: 728px; } } @@ -182,9 +183,18 @@ body > header { color: #069; font-size: 13pt; } +#global { + order: 0; +} +#logo { + order: 1; +} +#header-right { + order: 2; +} #logo { height: 36px; - margin: 0 25px 0 20px; + margin: 0 10px 0 10px; width: 110px; } #logo a { @@ -198,31 +208,35 @@ body > header { white-space: nowrap; width: 110px; } +#global { + flex-grow: 1; +} #global > ul { display: flex; } +#header-right > .a-login, +#site-search, +#post, #global li { margin: 0 10px; } -#search { - margin: 0; -} -#search input, -#user-menu-dropdown input { - background: #FFF; - border: 1px solid #DDDDD5; - padding: 4px; +#header-right { + align-items: center; + display: flex; + flex-grow: 1; } - -#menu-spacer-1, -#menu-expander { - display: none; +#site-search { + color: #069; + display: flex; } -#menu-expander { - align-self: center; - cursor: pointer; - padding: 10px; +#site-search input { + background: #f2f2ec; + border: 0; + border-bottom: 1px solid rgba(0, 104, 153, 0.5); /* #069 + alpha */ + margin: 0; + width: 120px; } + #user-menu { align-self: stretch; display: flex; @@ -239,13 +253,6 @@ body > header { margin: 10px; user-select: none; } -body:not([data-hash]) #user-menu > img { - display: none; -} -body:not([data-hash]) #user-menu > #menu-expander { - display: block; - order: 3; -} #user-menu-dropdown { background: #f2f2ec; box-shadow: 0 2px 9px 0 rgba(0, 0, 0, 0.28); @@ -264,145 +271,125 @@ body:not([data-hash]) #user-menu > #menu-expander { flex-direction: column; flex-grow: 1; margin: -1px 0 1px 0; -} -#user-menu-dropdown > ul.right-column { min-width: 9em; - order: 1; -} -#user-menu-dropdown > ul.left-column { - display: none; - flex-grow: 100; - min-width: 11em; - order: 0; -} -#user-menu-dropdown > ul.left-column input { - max-width: 12em; - width: 100%; -} -#user-menu-dropdown li { - padding: 6px; } +#user-menu-dropdown li > form, #user-menu-dropdown li > a { display: block; + padding: 6px; +} +#user-menu-dropdown li > a:hover { + background-color: #fff; + transition: background-color 0.2s ease-in; } #user-menu-dropdown li > a .icon { margin-right: 0.25em; } -#user-menu-dropdown li:first-child, #user-menu-dropdown li.next-section { border-top: 1px solid #ccc; } #user-menu-dropdown .icon--ei-share-apple { transform: rotate(90deg); } -#menu-photos-2, -#menu-popular-2 { +.show-1, +.show-2, +.show-3, +.show-4 { display: none; } -@media screen and (min-width: 710px) { - #user-menu:hover > #user-menu-dropdown { - display: flex; +@media screen and (max-width: 49.375em /* 790/16 */) { + #site-search, + .only-icon-1 span, + .hide-1 { + display: none; } -} - -@media screen and (max-width: 850px) { - #logo { - margin: 0 10px 0 10px; + .show-1 { + display: inline-block; } } -@media screen and (max-width: 710px) { - #user-menu { - flex-grow: 1; +@media screen and (max-width: 38.75em /* 620/16 */) { + #header-right > .a-login, + #post, + #global li { + margin: 0 6px; } - #user-menu-dropdown { - border: 10px solid #f2f2ec; - overflow: hidden; - width: 100vw; + #header_wrapper { + min-height: 48px; } - #user-menu-dropdown > ul.left-column { - display: flex; + #header_wrapper a { + font-size: 12pt; } - #menu-expander, - #menu-spacer-1 { - display: block; + #user-menu > img { + margin: 6px; } - #search, - #menu-spacer-2 { + .only-icon-2 span, + .hide-2 { display: none; } + .show-2 { + display: inline-block; + } } -@media screen and (max-width: 600px) { - #global li { - margin: 0 10px; +@media screen and (max-width: 32em /* 512/16 */) { + #user-menu-dropdown { + border: 10px solid #f2f2ec; + overflow: hidden; + width: 100vw; } - #menu-photos-1 { + .only-icon-3 span, + .hide-3 { display: none; } - #menu-photos-2 { + .show-3 { display: inline-block; } } -@media screen and (max-width: 470px) { - #logo { +@media screen and (max-width: 25.625em /* 410/16 */) { + .only-icon-4 span, + .hide-4 { display: none; } - #menu-popular-2 { + .show-4 { display: inline-block; } - #user-menu > img { - margin: 6px; - } - #header_wrapper { - min-height: 48px; - } - #header_wrapper a { - font-size: 12pt; - } -} - -@media screen and (max-width: 350px) { - #user-menu-dropdown > ul.left-column input { - max-width: 100%; - } } /* #endregion */ /* #region left column internals */ -.toolbar { - border-top: 1px solid #CCC; -} - -#column ul, -#column p, -#column hr { +#column > ul, +#column > hr { margin: 10px 0; } -#column > *:not(#ustats) li > a { +#column li > a, +#column li > p { display: block; - height: 100%; padding: 6px; } -#column > *:not(#ustats) li > a:hover { +#column li > a:hover { background-color: #f2f2ec; box-shadow: 0 0 3px rgba(0, 0, 0, 0.16); transition: background-color 0.2s ease-in; } -#column .margtop { - margin-top: 15px; +#column li span { + float: right; } -#column p { +#column li > p, +#column li span { + color: #999; +} +#column > form { + margin-bottom: 10px; +} +#column > form > p { font-size: 10pt; line-height: 140%; } -#column .tags { - text-align: justify; -} #column .inp { background: #F5F5E9; border: 1px solid #CCC; @@ -411,30 +398,20 @@ body:not([data-hash]) #user-menu > #menu-expander { width: 222px; } #ctitle { - align-items: center; display: flex; - flex-direction: row; font-size: 14pt; + position: relative; } #ctitle img { margin-right: 5px; max-width: 48px; vertical-align: middle; } -#ustats li { - font-size: 10pt; - margin: 3px 0; -} -#column table.iread { - width: 100%; -} -#column table.iread td { +#ctags a { + display: inline-block; + min-width: 25px; text-align: center; } -#column table.iread img { - height: 48px; - width: 48px; -} #column-expander { cursor: pointer; @@ -443,41 +420,59 @@ body:not([data-hash]) #user-menu > #menu-expander { text-align: end; } -@media screen and (min-width: 1001px) { +@media screen and (min-width: 1001px) and (min-height: 750px) { #column { position: sticky; - top: 60px; + top: 67px; /* #wrapper margin-top + #column margin-top */ } } @media screen and (max-width: 1000px) { #column-expander { - display: block; + align-items: center; + display: flex; + height: 100%; + justify-content: flex-end; + position: absolute; + width: 100%; } #column:not(.expanded) > *:not(#ctitle) { display: none; } - ul.toolbar { - display: flex; - justify-content: space-around; - padding-top: 10px; - } - #ustats ul { + + #column { display: flex; flex-flow: row wrap; - justify-content: space-around; + justify-content: space-between; + } + #ctitle, + #ctags, + #column > hr { + width: 100%; } - #ustats li { - margin: 3px 6px; + #column > ul { + flex-grow: 1; + margin: 0; + max-width: 300px; + } + #column > hr + ul:not(.toolbar) { + max-width: 100%; } } @media screen and (max-width: 470px) { + #column > form, #column .inp { width: 100%; } - #ustats li { - width: 45%; + #column > ul { + max-width: 100%; + } + #column > ul.toolbar { + display: flex; + justify-content: space-between; + margin-bottom: 10px; + width: 100%; } } @@ -721,7 +716,7 @@ li.msgthread .msg-cont { } } -@media screen and (max-width: 500px) { +@media screen and (max-width: 32em /* 512/16 */) { article > nav.l > a > span, .msg-cont > nav.l > a > span { display: none; @@ -745,7 +740,8 @@ q:before, q:after { content: ""; } -q, blockquote { +q, +blockquote { border-left: 3px solid #CCC; color: #666; display: block; diff --git a/juick-www/src/main/webapp/WEB-INF/views/index.html b/juick-www/src/main/webapp/WEB-INF/views/index.html index 10539c44..ccab381b 100644 --- a/juick-www/src/main/webapp/WEB-INF/views/index.html +++ b/juick-www/src/main/webapp/WEB-INF/views/index.html @@ -14,8 +14,6 @@ {% block "column" %} {% if tag | default('') is not empty %} {% include "views/partial/tagcolumn" %} -{% elseif visitor.uid > 0 %} -{% include "views/partial/usercolumn" %} {% else %} {% include "views/partial/homecolumn" %} {% endif %} diff --git a/juick-www/src/main/webapp/WEB-INF/views/partial/homecolumn.html b/juick-www/src/main/webapp/WEB-INF/views/partial/homecolumn.html index c466a128..50f7e725 100644 --- a/juick-www/src/main/webapp/WEB-INF/views/partial/homecolumn.html +++ b/juick-www/src/main/webapp/WEB-INF/views/partial/homecolumn.html @@ -1,6 +1,40 @@ -

+

+

{{ title }}

+
+
+
+ +
+
+

+ +

+
+
{% include "views/partial/tags" %} {% if showAdv | default(false) %} конструктор сайтов {% endif %} -

\ No newline at end of file +
\ No newline at end of file diff --git a/juick-www/src/main/webapp/WEB-INF/views/partial/navigation.html b/juick-www/src/main/webapp/WEB-INF/views/partial/navigation.html index ff845ce9..5056b3f3 100644 --- a/juick-www/src/main/webapp/WEB-INF/views/partial/navigation.html +++ b/juick-www/src/main/webapp/WEB-INF/views/partial/navigation.html @@ -1,50 +1,51 @@
diff --git a/juick-www/src/main/webapp/WEB-INF/views/partial/tagcolumn.html b/juick-www/src/main/webapp/WEB-INF/views/partial/tagcolumn.html index 3e61d3d3..16eadc1b 100644 --- a/juick-www/src/main/webapp/WEB-INF/views/partial/tagcolumn.html +++ b/juick-www/src/main/webapp/WEB-INF/views/partial/tagcolumn.html @@ -1,6 +1,7 @@

*{{ tag.name }}

+
{% if visitor is not empty and visitor.uid > 0 %}
    {% if isSubscribed %} @@ -30,4 +31,11 @@ {% endif %}
+ {% endif %} diff --git a/juick-www/src/main/webapp/WEB-INF/views/partial/usercolumn.html b/juick-www/src/main/webapp/WEB-INF/views/partial/usercolumn.html index 0906218a..27cde3a3 100644 --- a/juick-www/src/main/webapp/WEB-INF/views/partial/usercolumn.html +++ b/juick-www/src/main/webapp/WEB-INF/views/partial/usercolumn.html @@ -4,6 +4,7 @@
+
{% if visitor is not empty and visitor.uid > 0 and visitor.uid != user.uid %}
    {% if isSubscribed %} @@ -40,29 +41,48 @@ {% endif %}
-{% else %} -
{% endif %}
-

+

+
{% include "views/partial/usertags" %} +

- {% if iread is not empty %}
{% for u in iread %} @@ -74,5 +94,4 @@ {% endfor %}
{% endif %} -
-- cgit v1.2.3