diff --git a/build.sh b/build.sh index 304e42a64be5c418ea98d2945c729c010dfa3f43..8b43f60e87ada57a1c0035820f11c37f5c34ab14 100755 --- a/build.sh +++ b/build.sh @@ -1,20 +1,5 @@ #!/bin/sh -# ========================================================= -# CONFIGURATION -# ========================================================= - -# configuration for remote deploy, requirements: -# * curl -# * a recent tomcat server is required (8+) -# * a user that is allowed to deploy, with following roles: tomcat, manager-gui, manager-script, manager-jmx, manager-status -# * installed and running tomcat manager application -DEPLOY="true" -TOMCAT_HOST="localhost" -TOMCAT_PORT="8000" -TOMCAT_USER="tomcat" -TOMCAT_PW="tomcat" - # ========================================================= # DO NOT EDIT AFTER THIS POINT # ========================================================= @@ -75,13 +60,5 @@ if [ $? -ne 0 ]; then exit 1 fi -if [ $DEPLOY = "true" ]; then - echo "" >> $LOG - echo "-------------------------------" >> $LOG - echo "deploying vipra-rest" | tee -a $LOG - echo "-------------------------------" >> $LOG - curl "http://$TOMCAT_USER:TOMCAT_PW@$TOMCAT_HOST:$TOMCAT_PORT/manager/text/deploy?path=/vipra-rest&update=true" --upload-file ./vipra-rest/target/vipra-rest.war >> $LOG 2>&1 -fi - echo "complete" exit $? diff --git a/ma-impl.sublime-workspace b/ma-impl.sublime-workspace index 7c5b9bb10d9edbca297a7daa966258ae733304dd..0b75fa13f7a32cb8e9bfc3bd2566f078e749bdb0 100644 --- a/ma-impl.sublime-workspace +++ b/ma-impl.sublime-workspace @@ -3,6 +3,14 @@ { "selected_items": [ + [ + "angular", + "angular-ui-router" + ], + [ + "state", + "stateProvider" + ], [ "border-top", "border-top-style" @@ -279,43 +287,11 @@ }, "buffers": [ - { - "file": "vipra-ui/index.html", - "settings": - { - "buffer_size": 1013, - "line_ending": "Unix" - } - }, - { - "file": "vipra-ui/js/app.js", - "settings": - { - "buffer_size": 326, - "line_ending": "Unix" - } - }, { "file": "vipra-ui/js/controllers.js", "settings": { - "buffer_size": 102, - "line_ending": "Unix" - } - }, - { - "file": "vipra-ui/js/directives.js", - "settings": - { - "buffer_size": 49, - "line_ending": "Unix" - } - }, - { - "file": "vipra-ui/js/services.js", - "settings": - { - "buffer_size": 47, + "buffer_size": 1591, "line_ending": "Unix" } } @@ -499,21 +475,39 @@ [ "/home/eike/repos/master/ma-impl", "/home/eike/repos/master/ma-impl/vipra-ui", - "/home/eike/repos/master/ma-impl/vipra-ui/bower_components/angular", - "/home/eike/repos/master/ma-impl/vipra-ui/bower_components/angular-resource", - "/home/eike/repos/master/ma-impl/vipra-ui/bower_components/angular-ui-router", "/home/eike/repos/master/ma-impl/vipra-ui/bower_components/angular-ui-router/release", - "/home/eike/repos/master/ma-impl/vipra-ui/bower_components/bootstrap/dist/js", + "/home/eike/repos/master/ma-impl/vipra-ui/bower_components/bootstrap/dist", "/home/eike/repos/master/ma-impl/vipra-ui/bower_components/jquery/dist", + "/home/eike/repos/master/ma-impl/vipra-ui/css", "/home/eike/repos/master/ma-impl/vipra-ui/html", "/home/eike/repos/master/ma-impl/vipra-ui/js" ], "file_history": [ + "/home/eike/repos/master/ma-impl/vipra-ui/js/app.js", "/home/eike/repos/master/ma-impl/vipra-ui/html/index.html", - "/home/eike/repos/master/ma-impl/vipra-ui/css/main.less", - "/home/eike/repos/master/ma-impl/vipra-ui/gulpfile.js", + "/home/eike/repos/master/ma-impl/vipra-ui/css/app.less", "/home/eike/repos/master/ma-impl/vipra-ui/index.html", + "/run/user/1000/gvfs/smb-share:server=eike-ain,share=share/interceptors.js", + "/home/eike/repos/master/ma-impl/vipra-ui/js/factories.js", + "/home/eike/repos/master/ma-impl/vipra-ui/js/controllers.js", + "/home/eike/repos/master/ma-impl/vipra-ui/html/topics/index.html", + "/home/eike/repos/master/ma-impl/vipra-ui/html/topics/show.html", + "/home/eike/repos/master/ma-impl/vipra-ui/html/words/index.html", + "/home/eike/repos/master/ma-impl/vipra-ui/html/words/show.html", + "/home/eike/repos/master/ma-impl/vipra-ui/gulpfile.js", + "/home/eike/repos/master/ma-impl/vipra-ui/css/footer.less", + "/home/eike/repos/master/ma-impl/vipra-ui/less/vendor.less", + "/home/eike/repos/master/ma-impl/vipra-ui/less/vendor.less.css", + "/home/eike/repos/master/ma-impl/vipra-ui/less/app.less", + "/home/eike/repos/master/ma-impl/vipra-ui/public/index.html", + "/home/eike/repos/master/ma-impl/vipra-ui/js/vendor.js", + "/home/eike/repos/master/ma-impl/vipra-ui/less/main.less", + "/home/eike/repos/master/ma-impl/vipra-ui/js/directives.js", + "/home/eike/repos/master/ma-impl/vipra-ui/js/services.js", + "/home/eike/repos/master/ma-impl/vipra-ui/html/articles/show.html", + "/home/eike/repos/master/ma-impl/vipra-ui/html/articles/index.html", + "/home/eike/repos/master/ma-impl/vipra-ui/css/main.less", "/home/eike/.config/sublime-text-3/Packages/User/Preferences.sublime-settings", "/home/eike/repos/master/ma-impl/vipra-ui/app/adapters/application.js", "/home/eike/repos/master/ma-impl/vipra-ui/app/styles/app.scss", @@ -617,27 +611,7 @@ "/home/eike/repos/master/ma-impl/vm/config/environment", "/home/eike/repos/master/ma-impl/vm/config/initd-tomcat", "/home/eike/Repositories/fu/ss15/ma/impl/TODO", - "/home/eike/.local/share/vipra/jgibb/vocab", - "/home/eike/.local/share/vipra/jgibb/index", - "/home/eike/.local/share/vipra/jgibb/jgibb.phi", - "/home/eike/Downloads/JGibbLDA-v.1.0/src/jgibblda/Constants.java", - "/home/eike/Downloads/JGibbLDA-v.1.0/models/casestudy-en/model-final.others", - "/home/eike/Downloads/JGibbLDA-v.1.0/models/casestudy-en/model-final.twords", - "/home/eike/Downloads/JGibbLDA-v.1.0/models/casestudy-en/newdocs.dat", - "/home/eike/Repositories/fu/ss15/ma/impl/vm/data/data.json", - "/home/eike/Repositories/fu/ss15/ma/impl/vm/data/test-2.json", - "/home/eike/Repositories/fu/ss15/ma/impl/vm/data/test-1.json", - "/home/eike/.cache/.fr-rPaUI0/LICENSE.txt", - "/home/eike/Repositories/fu/ss15/ma/impl/vipra-rest/src/main/resources/log4j2.xml", - "/home/eike/Repositories/fu/ss15/ma/impl/vipra-config/log4j2.xml", - "/home/eike/Repositories/fu/ss15/ma/impl/vipra-cmd/test/test-1.json", - "/home/eike/Repositories/fu/ss15/ma/impl/vipra-cmd/vipra-cmd.sh", - "/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/components/article-list.js", - "/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/components/text-marker.js", - "/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/components/debounced-input.js", - "/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/components/dynamic-high-charts.js", - "/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/components/text-marker.hbs", - "/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/components/article-list.hbs" + "/home/eike/.local/share/vipra/jgibb/vocab" ], "find": { @@ -961,29 +935,29 @@ "groups": [ { - "selected": 2, + "selected": 0, "sheets": [ { "buffer": 0, - "file": "vipra-ui/index.html", + "file": "vipra-ui/js/controllers.js", "semi_transient": false, "settings": { - "buffer_size": 1013, + "buffer_size": 1591, "regions": { }, "selection": [ [ - 239, - 239 + 1057, + 1057 ] ], "settings": { - "syntax": "Packages/HTML/HTML.tmLanguage", + "syntax": "Packages/JavaScriptNext - ES6 Syntax/JavaScriptNext.tmLanguage", "tab_size": 2, "translate_tabs_to_spaces": true }, @@ -991,124 +965,8 @@ "translation.y": 0.0, "zoom_level": 1.0 }, - "stack_index": 2, - "type": "text" - }, - { - "buffer": 1, - "file": "vipra-ui/js/app.js", - "semi_transient": false, - "settings": - { - "buffer_size": 326, - "regions": - { - }, - "selection": - [ - [ - 321, - 321 - ] - ], - "settings": - { - "open_with_edit": true, - "syntax": "Packages/JavaScriptNext - ES6 Syntax/JavaScriptNext.tmLanguage" - }, - "translation.x": 0.0, - "translation.y": 0.0, - "zoom_level": 1.0 - }, - "stack_index": 1, - "type": "text" - }, - { - "buffer": 2, - "file": "vipra-ui/js/controllers.js", - "semi_transient": false, - "settings": - { - "buffer_size": 102, - "regions": - { - }, - "selection": - [ - [ - 102, - 102 - ] - ], - "settings": - { - "open_with_edit": true, - "syntax": "Packages/JavaScriptNext - ES6 Syntax/JavaScriptNext.tmLanguage" - }, - "translation.x": 0.0, - "translation.y": 0.0, - "zoom_level": 1.0 - }, "stack_index": 0, "type": "text" - }, - { - "buffer": 3, - "file": "vipra-ui/js/directives.js", - "semi_transient": false, - "settings": - { - "buffer_size": 49, - "regions": - { - }, - "selection": - [ - [ - 42, - 42 - ] - ], - "settings": - { - "open_with_edit": true, - "syntax": "Packages/JavaScriptNext - ES6 Syntax/JavaScriptNext.tmLanguage" - }, - "translation.x": 0.0, - "translation.y": 0.0, - "zoom_level": 1.0 - }, - "stack_index": 3, - "type": "text" - }, - { - "buffer": 4, - "file": "vipra-ui/js/services.js", - "semi_transient": false, - "settings": - { - "buffer_size": 47, - "regions": - { - }, - "selection": - [ - [ - 40, - 40 - ] - ], - "settings": - { - "open_with_edit": true, - "syntax": "Packages/JavaScriptNext - ES6 Syntax/JavaScriptNext.tmLanguage" - }, - "translation.x": 0.0, - "translation.y": 0.0, - "zoom_level": 1.0 - }, - "stack_index": 4, - "type": "text" } ] } @@ -1276,7 +1134,7 @@ "show_open_files": true, "show_tabs": true, "side_bar_visible": true, - "side_bar_width": 295.0, + "side_bar_width": 274.0, "status_bar_visible": true, "template_settings": { diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java index 6b7791a5a7e25627d759b1037c390bb28f5cb0bc..a919f92ab5273cf3cad2d0c12783f89bef1724d1 100644 --- a/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java +++ b/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java @@ -5,9 +5,7 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.util.ArrayList; import java.util.List; -import java.util.Map; import javax.servlet.ServletContext; import javax.ws.rs.Consumes; @@ -29,17 +27,11 @@ import org.bson.types.ObjectId; import org.ehcache.Cache; import org.ehcache.CacheManager; import org.ehcache.config.CacheConfigurationBuilder; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.client.transport.TransportClient; -import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.search.SearchHit; -import org.elasticsearch.search.SearchHits; import de.vipra.rest.Messages; import de.vipra.rest.model.APIError; import de.vipra.rest.model.Wrapper; import de.vipra.util.Config; -import de.vipra.util.ESClient; import de.vipra.util.MongoUtils; import de.vipra.util.StringUtils; import de.vipra.util.ex.ConfigException; @@ -55,7 +47,6 @@ public class ArticleResource { final Cache<String, ArticleFull> cache; final DatabaseService<ArticleFull, ObjectId> service; - final TransportClient client; public ArticleResource(@Context ServletContext servletContext) throws ConfigException, IOException { Config config = Config.getConfig(); @@ -67,8 +58,6 @@ public class ArticleResource { articleCache = manager.createCache("articlecache", CacheConfigurationBuilder.newCacheConfigurationBuilder() .buildConfig(String.class, ArticleFull.class)); this.cache = articleCache; - - client = ESClient.getClient(config); } @GET @@ -76,13 +65,6 @@ public class ArticleResource { public Response getArticles(@QueryParam("skip") Integer skip, @QueryParam("limit") Integer limit, @QueryParam("sort") @DefaultValue("date") String sortBy, @QueryParam("fields") String fields, @QueryParam("query") String query) { - if (query == null) - return getArticlesFromDb(skip, limit, sortBy, fields); - else - return getArticlesFromIndex(skip, limit, query); - } - - private Response getArticlesFromDb(Integer skip, Integer limit, String sortBy, String fields) { Wrapper<List<ArticleFull>> res = new Wrapper<>(); if (skip != null && limit != null) @@ -106,40 +88,6 @@ public class ArticleResource { } } - private Response getArticlesFromIndex(Integer skip, Integer limit, String query) { - Wrapper<List<ArticleFull>> res = new Wrapper<>(); - - if (skip == null || skip < 0) - skip = 0; - - if (limit == null || limit < 0) - limit = 20; - - SearchResponse response = null; - try { - response = client.prepareSearch("articles").setQuery(QueryBuilders.multiMatchQuery(query, "_all")) - .setFrom(skip).setSize(limit).execute().actionGet(); - } catch (Exception e) { - res.addError(new APIError(Response.Status.BAD_REQUEST, "Error", e.getMessage())); - return res.badRequest(); - } - - SearchHits hits = response.getHits(); - List<ArticleFull> articles = new ArrayList<>(10); - for (SearchHit hit : hits) { - Map<String, Object> source = hit.getSource(); - ArticleFull article = new ArticleFull(); - article.setId(MongoUtils.objectId(hit.getId())); - article.setTitle(source.get("title").toString()); - article.setText(StringUtils.ellipsize(source.get("text").toString(), 150)); - articles.add(article); - } - - res.addMeta("total", articles.size()); - - return res.ok(articles); - } - @GET @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/SearchResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/SearchResource.java new file mode 100644 index 0000000000000000000000000000000000000000..530ec3610d78b560292547c59aed293e315b1c03 --- /dev/null +++ b/vipra-rest/src/main/java/de/vipra/rest/resource/SearchResource.java @@ -0,0 +1,87 @@ +package de.vipra.rest.resource; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletContext; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.SearchHits; + +import de.vipra.rest.model.APIError; +import de.vipra.rest.model.Wrapper; +import de.vipra.util.Config; +import de.vipra.util.ESClient; +import de.vipra.util.MongoUtils; +import de.vipra.util.StringUtils; +import de.vipra.util.ex.ConfigException; +import de.vipra.util.model.ArticleFull; + +@Path("/search") +public class SearchResource { + + @Context + UriInfo uri; + + final TransportClient client; + + public SearchResource(@Context ServletContext servletContext) throws ConfigException, IOException { + Config config = Config.getConfig(); + + client = ESClient.getClient(config); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response doSearch(@QueryParam("skip") Integer skip, @QueryParam("limit") Integer limit, + @QueryParam("query") String query) { + Wrapper<List<ArticleFull>> res = new Wrapper<>(); + + if (skip == null || skip < 0) + skip = 0; + + if (limit == null || limit < 0) + limit = 20; + + if (query == null || query.isEmpty() || limit == 0) + return res.noContent(); + + SearchResponse response = null; + try { + response = client.prepareSearch("articles").setQuery(QueryBuilders.multiMatchQuery(query, "_all")) + .setFrom(skip).setSize(limit).execute().actionGet(); + } catch (Exception e) { + res.addError(new APIError(Response.Status.BAD_REQUEST, "Error", e.getMessage())); + return res.badRequest(); + } + + SearchHits hits = response.getHits(); + List<ArticleFull> articles = new ArrayList<>(10); + for (SearchHit hit : hits) { + Map<String, Object> source = hit.getSource(); + ArticleFull article = new ArticleFull(); + article.setId(MongoUtils.objectId(hit.getId())); + article.setTitle(source.get("title").toString()); + article.setText(StringUtils.ellipsize(source.get("text").toString(), 150)); + articles.add(article); + } + + res.addMeta("total", articles.size()); + + return res.ok(articles); + } + +} diff --git a/vipra-ui/css/app.css b/vipra-ui/css/app.css new file mode 100644 index 0000000000000000000000000000000000000000..dd2e3404b6c36783e3eb7f46be657a3b84e4e14b --- /dev/null +++ b/vipra-ui/css/app.css @@ -0,0 +1,2 @@ +html{position:relative;min-height:100%}body{padding-bottom:20px;margin-bottom:60px}.word{cursor:pointer;padding-right:5px}.center{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.loading{background:url(/assets/images/squares.gif) no-repeat center center;width:120px;height:120px}.heading{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;font-size:82px;margin:30px 0;background:transparent url(/img/logo.png) no-repeat 50% 50%;min-width:272px;min-height:216px;padding-top:90px}.ellipsize{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.search-result{margin-bottom:5px}.navbar-default .collapse:not(.in) .navbar-nav>.active>a,.navbar-default .collapse:not(.in) .navbar-nav>.active>a:focus,.navbar-default .collapse:not(.in) .navbar-nav>.active>a:hover{border-bottom:3px solid;padding-bottom:12px}.footer{position:absolute;bottom:0;width:100%;height:50px;border-top-width:1px;border-top-style:solid}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default} +/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFwcC5sZXNzIiwiYXBwLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxLQUNFLGtCQUFBLEFBQ0EsZUFBQSxDQ0NELEFERUQsS0FDRSxvQkFBQSxBQUVBLGtCQUFBLENDQUQsQURHRCxNQUNFLGVBQUEsQUFDQSxpQkFBQSxDQ0RELEFESUQsUUFDRSxrQkFBQSxBQUNBLFFBQUEsQUFDQSxTQUFBLEFBQ0EsOEJBQUEsQ0NGRCxBREtELFNBQ0UsbUVBQUEsQUFDQSxZQUFBLEFBQ0EsWUFBQSxDQ0hELEFETUQsU0E0Q0UsMkJBQUEsQUFDQSx5QkFBQSxBQUNBLHNCQUFBLEFBQ0EscUJBQUEsQUFDQSxpQkFBQSxBQUNBLGVBQUEsQUEvQ0EsZUFBQSxBQUNBLGNBQUEsQUFDQSw0REFBQSxBQUNBLGdCQUFBLEFBQ0EsaUJBQUEsQUFDQSxnQkFBQSxDQ0NELEFERUQsV0FDRSxtQkFBQSxBQUNBLGdCQUFBLEFBQ0Esc0JBQUEsQ0NBRCxBREdELGVBQ0UsaUJBQUEsQ0NERCxBRE9LLHVMQUdFLHdCQUFBLEFBQ0EsbUJBQUEsQ0NMUCxBRFdELFFBQ0Usa0JBQUEsQUFDQSxTQUFBLEFBQ0EsV0FBQSxBQUVBLFlBQUEsQUFDQSxxQkFBQSxBQUNBLHNCQUFBLENDVEQsQURZRCxVQUNFLDJCQUFBLEFBQ0EseUJBQUEsQUFDQSxzQkFBQSxBQUNBLHFCQUFBLEFBQ0EsaUJBQUEsQUFDQSxjQUFBLENDVkQiLCJmaWxlIjoiYXBwLmNzcyIsInNvdXJjZXNDb250ZW50IjpbImh0bWwge1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIG1pbi1oZWlnaHQ6IDEwMCU7XG59XG5cbmJvZHkge1xuICBwYWRkaW5nLWJvdHRvbTogMjBweDtcbiAgLyogTWFyZ2luIGJvdHRvbSBieSBmb290ZXIgaGVpZ2h0ICovXG4gIG1hcmdpbi1ib3R0b206IDYwcHg7XG59XG5cbi53b3JkIHtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBwYWRkaW5nLXJpZ2h0OiA1cHg7XG59XG5cbi5jZW50ZXIge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogNTAlO1xuICBsZWZ0OiA1MCU7XG4gIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpO1xufVxuXG4ubG9hZGluZyB7XG4gIGJhY2tncm91bmQ6IHVybCgvYXNzZXRzL2ltYWdlcy9zcXVhcmVzLmdpZikgbm8tcmVwZWF0IGNlbnRlciBjZW50ZXI7XG4gIHdpZHRoOiAxMjBweDtcbiAgaGVpZ2h0OiAxMjBweDtcbn1cblxuLmhlYWRpbmcge1xuICAubm9zZWxlY3Q7XG4gIGZvbnQtc2l6ZTogODJweDtcbiAgbWFyZ2luOiAzMHB4IDA7XG4gIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50IHVybCgvaW1nL2xvZ28ucG5nKSBuby1yZXBlYXQgNTAlIDUwJTtcbiAgbWluLXdpZHRoOiAyNzJweDtcbiAgbWluLWhlaWdodDogMjE2cHg7XG4gIHBhZGRpbmctdG9wOiA5MHB4O1xufVxuXG4uZWxsaXBzaXplIHtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XG59XG5cbi5zZWFyY2gtcmVzdWx0IHtcbiAgbWFyZ2luLWJvdHRvbTogNXB4O1xufVxuXG4ubmF2YmFyLWRlZmF1bHQge1xuICAuY29sbGFwc2U6bm90KC5pbikge1xuICAgIC5uYXZiYXItbmF2ID4gLmFjdGl2ZSB7XG4gICAgICAmPiBhLFxuICAgICAgJj4gYTpob3ZlcixcbiAgICAgICY+IGE6Zm9jdXMge1xuICAgICAgICBib3JkZXItYm90dG9tOiAzcHggc29saWQ7XG4gICAgICAgIHBhZGRpbmctYm90dG9tOiAxMnB4O1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG4uZm9vdGVyIHtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBib3R0b206IDA7XG4gIHdpZHRoOiAxMDAlO1xuICAvKiBTZXQgdGhlIGZpeGVkIGhlaWdodCBvZiB0aGUgZm9vdGVyIGhlcmUgKi9cbiAgaGVpZ2h0OiA1MHB4O1xuICBib3JkZXItdG9wLXdpZHRoOiAxcHg7XG4gIGJvcmRlci10b3Atc3R5bGU6IHNvbGlkO1xufVxuXG4ubm9zZWxlY3Qge1xuICAtd2Via2l0LXRvdWNoLWNhbGxvdXQ6IG5vbmU7XG4gIC13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tb3otdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tcy11c2VyLXNlbGVjdDogbm9uZTtcbiAgdXNlci1zZWxlY3Q6IG5vbmU7XG4gIGN1cnNvcjogZGVmYXVsdDtcbn0iLCJodG1sIHtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBtaW4taGVpZ2h0OiAxMDAlO1xufVxuYm9keSB7XG4gIHBhZGRpbmctYm90dG9tOiAyMHB4O1xuICAvKiBNYXJnaW4gYm90dG9tIGJ5IGZvb3RlciBoZWlnaHQgKi9cbiAgbWFyZ2luLWJvdHRvbTogNjBweDtcbn1cbi53b3JkIHtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBwYWRkaW5nLXJpZ2h0OiA1cHg7XG59XG4uY2VudGVyIHtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB0b3A6IDUwJTtcbiAgbGVmdDogNTAlO1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNTAlKTtcbn1cbi5sb2FkaW5nIHtcbiAgYmFja2dyb3VuZDogdXJsKC9hc3NldHMvaW1hZ2VzL3NxdWFyZXMuZ2lmKSBuby1yZXBlYXQgY2VudGVyIGNlbnRlcjtcbiAgd2lkdGg6IDEyMHB4O1xuICBoZWlnaHQ6IDEyMHB4O1xufVxuLmhlYWRpbmcge1xuICAtd2Via2l0LXRvdWNoLWNhbGxvdXQ6IG5vbmU7XG4gIC13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tb3otdXNlci1zZWxlY3Q6IG5vbmU7XG4gIC1tcy11c2VyLXNlbGVjdDogbm9uZTtcbiAgdXNlci1zZWxlY3Q6IG5vbmU7XG4gIGN1cnNvcjogZGVmYXVsdDtcbiAgZm9udC1zaXplOiA4MnB4O1xuICBtYXJnaW46IDMwcHggMDtcbiAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQgdXJsKC9pbWcvbG9nby5wbmcpIG5vLXJlcGVhdCA1MCUgNTAlO1xuICBtaW4td2lkdGg6IDI3MnB4O1xuICBtaW4taGVpZ2h0OiAyMTZweDtcbiAgcGFkZGluZy10b3A6IDkwcHg7XG59XG4uZWxsaXBzaXplIHtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XG59XG4uc2VhcmNoLXJlc3VsdCB7XG4gIG1hcmdpbi1ib3R0b206IDVweDtcbn1cbi5uYXZiYXItZGVmYXVsdCAuY29sbGFwc2U6bm90KC5pbikgLm5hdmJhci1uYXYgPiAuYWN0aXZlID4gYSxcbi5uYXZiYXItZGVmYXVsdCAuY29sbGFwc2U6bm90KC5pbikgLm5hdmJhci1uYXYgPiAuYWN0aXZlID4gYTpob3Zlcixcbi5uYXZiYXItZGVmYXVsdCAuY29sbGFwc2U6bm90KC5pbikgLm5hdmJhci1uYXYgPiAuYWN0aXZlID4gYTpmb2N1cyB7XG4gIGJvcmRlci1ib3R0b206IDNweCBzb2xpZDtcbiAgcGFkZGluZy1ib3R0b206IDEycHg7XG59XG4uZm9vdGVyIHtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBib3R0b206IDA7XG4gIHdpZHRoOiAxMDAlO1xuICAvKiBTZXQgdGhlIGZpeGVkIGhlaWdodCBvZiB0aGUgZm9vdGVyIGhlcmUgKi9cbiAgaGVpZ2h0OiA1MHB4O1xuICBib3JkZXItdG9wLXdpZHRoOiAxcHg7XG4gIGJvcmRlci10b3Atc3R5bGU6IHNvbGlkO1xufVxuLm5vc2VsZWN0IHtcbiAgLXdlYmtpdC10b3VjaC1jYWxsb3V0OiBub25lO1xuICAtd2Via2l0LXVzZXItc2VsZWN0OiBub25lO1xuICAtbW96LXVzZXItc2VsZWN0OiBub25lO1xuICAtbXMtdXNlci1zZWxlY3Q6IG5vbmU7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuICBjdXJzb3I6IGRlZmF1bHQ7XG59XG4iXSwic291cmNlUm9vdCI6Ii9zb3VyY2UvIn0= */ diff --git a/vipra-ui/css/app.less b/vipra-ui/css/app.less new file mode 100644 index 0000000000000000000000000000000000000000..f08068ef03252e4220fffabfe9fea63ad1914870 --- /dev/null +++ b/vipra-ui/css/app.less @@ -0,0 +1,80 @@ +html { + position: relative; + min-height: 100%; +} + +body { + padding-bottom: 20px; + /* Margin bottom by footer height */ + margin-bottom: 60px; +} + +.word { + cursor: pointer; + padding-right: 5px; +} + +.center { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.loading { + background: url(/assets/images/squares.gif) no-repeat center center; + width: 120px; + height: 120px; +} + +.heading { + .noselect; + font-size: 82px; + margin: 30px 0; + background: transparent url(/img/logo.png) no-repeat 50% 50%; + min-width: 272px; + min-height: 216px; + padding-top: 90px; +} + +.ellipsize { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.search-result { + margin-bottom: 5px; +} + +.navbar-default { + .collapse:not(.in) { + .navbar-nav > .active { + &> a, + &> a:hover, + &> a:focus { + border-bottom: 3px solid; + padding-bottom: 12px; + } + } + } +} + +.footer { + position: absolute; + bottom: 0; + width: 100%; + /* Set the fixed height of the footer here */ + height: 50px; + border-top-width: 1px; + border-top-style: solid; +} + +.noselect { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: default; +} \ No newline at end of file diff --git a/vipra-ui/css/main.less b/vipra-ui/css/main.less deleted file mode 100644 index 27e5a0030710240b902e7c51598704f57ba2bdff..0000000000000000000000000000000000000000 --- a/vipra-ui/css/main.less +++ /dev/null @@ -1,3 +0,0 @@ -html, body { - background: red; -} \ No newline at end of file diff --git a/vipra-ui/favicon/android-chrome-144x144.png b/vipra-ui/favicon/android-chrome-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..23b3628a1c53b9d711e044621691e0230d960282 Binary files /dev/null and b/vipra-ui/favicon/android-chrome-144x144.png differ diff --git a/vipra-ui/favicon/android-chrome-192x192.png b/vipra-ui/favicon/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..ca42e62464c1d62bc966768bbad7a9719fd6cc47 Binary files /dev/null and b/vipra-ui/favicon/android-chrome-192x192.png differ diff --git a/vipra-ui/favicon/android-chrome-36x36.png b/vipra-ui/favicon/android-chrome-36x36.png new file mode 100644 index 0000000000000000000000000000000000000000..cf4620b3bb98a754e90415e7ad468b0e72dfa960 Binary files /dev/null and b/vipra-ui/favicon/android-chrome-36x36.png differ diff --git a/vipra-ui/favicon/android-chrome-48x48.png b/vipra-ui/favicon/android-chrome-48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..e9ee2f0428f4a37b2faf5c06770d6c77b656f19a Binary files /dev/null and b/vipra-ui/favicon/android-chrome-48x48.png differ diff --git a/vipra-ui/favicon/android-chrome-72x72.png b/vipra-ui/favicon/android-chrome-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..4f29e40d75691511cafb15f3bb6735f9c456ed67 Binary files /dev/null and b/vipra-ui/favicon/android-chrome-72x72.png differ diff --git a/vipra-ui/favicon/android-chrome-96x96.png b/vipra-ui/favicon/android-chrome-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..e42b114b5412839588e78595707b410fdcb7868e Binary files /dev/null and b/vipra-ui/favicon/android-chrome-96x96.png differ diff --git a/vipra-ui/favicon/apple-touch-icon-114x114.png b/vipra-ui/favicon/apple-touch-icon-114x114.png new file mode 100644 index 0000000000000000000000000000000000000000..3ce8caf70ec12fcadd16e355b9d43971eb7d8de9 Binary files /dev/null and b/vipra-ui/favicon/apple-touch-icon-114x114.png differ diff --git a/vipra-ui/favicon/apple-touch-icon-120x120.png b/vipra-ui/favicon/apple-touch-icon-120x120.png new file mode 100644 index 0000000000000000000000000000000000000000..3ed93796b41ae1522cc0467f1078fb97da48d46f Binary files /dev/null and b/vipra-ui/favicon/apple-touch-icon-120x120.png differ diff --git a/vipra-ui/favicon/apple-touch-icon-144x144.png b/vipra-ui/favicon/apple-touch-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..57956a0277ff1eb295a7a44ee33965831de36d93 Binary files /dev/null and b/vipra-ui/favicon/apple-touch-icon-144x144.png differ diff --git a/vipra-ui/favicon/apple-touch-icon-152x152.png b/vipra-ui/favicon/apple-touch-icon-152x152.png new file mode 100644 index 0000000000000000000000000000000000000000..d5004ac03673398fe6f7d418b00d2eea02bd0c42 Binary files /dev/null and b/vipra-ui/favicon/apple-touch-icon-152x152.png differ diff --git a/vipra-ui/favicon/apple-touch-icon-180x180.png b/vipra-ui/favicon/apple-touch-icon-180x180.png new file mode 100644 index 0000000000000000000000000000000000000000..c3de5f5a7023e83ec308380a38f385afa05de5f2 Binary files /dev/null and b/vipra-ui/favicon/apple-touch-icon-180x180.png differ diff --git a/vipra-ui/favicon/apple-touch-icon-57x57.png b/vipra-ui/favicon/apple-touch-icon-57x57.png new file mode 100644 index 0000000000000000000000000000000000000000..a44ba21162954e0bcc774d6745522175bb55e898 Binary files /dev/null and b/vipra-ui/favicon/apple-touch-icon-57x57.png differ diff --git a/vipra-ui/favicon/apple-touch-icon-60x60.png b/vipra-ui/favicon/apple-touch-icon-60x60.png new file mode 100644 index 0000000000000000000000000000000000000000..aad2e11b045c59e009a994ed274c0b3f5a682a80 Binary files /dev/null and b/vipra-ui/favicon/apple-touch-icon-60x60.png differ diff --git a/vipra-ui/favicon/apple-touch-icon-72x72.png b/vipra-ui/favicon/apple-touch-icon-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..8b4b2fcdaa5f0cd53c169b699db48c63e28b40cf Binary files /dev/null and b/vipra-ui/favicon/apple-touch-icon-72x72.png differ diff --git a/vipra-ui/favicon/apple-touch-icon-76x76.png b/vipra-ui/favicon/apple-touch-icon-76x76.png new file mode 100644 index 0000000000000000000000000000000000000000..e015e2a1bc495c1a39e8c5c7ab39d3187d9dd67b Binary files /dev/null and b/vipra-ui/favicon/apple-touch-icon-76x76.png differ diff --git a/vipra-ui/favicon/apple-touch-icon-precomposed.png b/vipra-ui/favicon/apple-touch-icon-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..cf4d130553bb1d08464f0e2576bb7cc1203d94d3 Binary files /dev/null and b/vipra-ui/favicon/apple-touch-icon-precomposed.png differ diff --git a/vipra-ui/favicon/apple-touch-icon.png b/vipra-ui/favicon/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c3de5f5a7023e83ec308380a38f385afa05de5f2 Binary files /dev/null and b/vipra-ui/favicon/apple-touch-icon.png differ diff --git a/vipra-ui/favicon/browserconfig.xml b/vipra-ui/favicon/browserconfig.xml new file mode 100644 index 0000000000000000000000000000000000000000..9ecd35003349383dc5417fe45d5b97a8842f3541 --- /dev/null +++ b/vipra-ui/favicon/browserconfig.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<browserconfig> + <msapplication> + <tile> + <square70x70logo src="/favicon/mstile-70x70.png"/> + <square150x150logo src="/favicon/mstile-150x150.png"/> + <square310x310logo src="/favicon/mstile-310x310.png"/> + <wide310x150logo src="/favicon/mstile-310x150.png"/> + <TileColor>#da532c</TileColor> + </tile> + </msapplication> +</browserconfig> diff --git a/vipra-ui/favicon/favicon-16x16.png b/vipra-ui/favicon/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..df7bc123350e7b54707f457eb2c623591914e1ed Binary files /dev/null and b/vipra-ui/favicon/favicon-16x16.png differ diff --git a/vipra-ui/favicon/favicon-194x194.png b/vipra-ui/favicon/favicon-194x194.png new file mode 100644 index 0000000000000000000000000000000000000000..e956726d2909bb3095e52cecc1311d0102706f5a Binary files /dev/null and b/vipra-ui/favicon/favicon-194x194.png differ diff --git a/vipra-ui/favicon/favicon-32x32.png b/vipra-ui/favicon/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..54a622eb15653b7821540cf0f4c3a0d9ac602c40 Binary files /dev/null and b/vipra-ui/favicon/favicon-32x32.png differ diff --git a/vipra-ui/favicon/favicon-96x96.png b/vipra-ui/favicon/favicon-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..984784f51e26962ecfa7eed0390f6d71f8bc2d86 Binary files /dev/null and b/vipra-ui/favicon/favicon-96x96.png differ diff --git a/vipra-ui/favicon/favicon.ico b/vipra-ui/favicon/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..82069d823ecf0ce9130f015ba9c2f54df0764982 Binary files /dev/null and b/vipra-ui/favicon/favicon.ico differ diff --git a/vipra-ui/favicon/manifest.json b/vipra-ui/favicon/manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..cab1e0a2b8a78dee0d05770b9cbb6a3eec6830a9 --- /dev/null +++ b/vipra-ui/favicon/manifest.json @@ -0,0 +1,41 @@ +{ + "name": "Vipra", + "icons": [ + { + "src": "\/favicon\/android-chrome-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": 0.75 + }, + { + "src": "\/favicon\/android-chrome-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": 1 + }, + { + "src": "\/favicon\/android-chrome-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": 1.5 + }, + { + "src": "\/favicon\/android-chrome-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": 2 + }, + { + "src": "\/favicon\/android-chrome-144x144.png", + "sizes": "144x144", + "type": "image\/png", + "density": 3 + }, + { + "src": "\/favicon\/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image\/png", + "density": 4 + } + ] +} diff --git a/vipra-ui/favicon/mstile-144x144.png b/vipra-ui/favicon/mstile-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..fe6ee38a065d4a60c239b34159cabe2657ca786f Binary files /dev/null and b/vipra-ui/favicon/mstile-144x144.png differ diff --git a/vipra-ui/favicon/mstile-150x150.png b/vipra-ui/favicon/mstile-150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..a7f5e77e38a09a5d124327aea41e3851a36776e7 Binary files /dev/null and b/vipra-ui/favicon/mstile-150x150.png differ diff --git a/vipra-ui/favicon/mstile-310x150.png b/vipra-ui/favicon/mstile-310x150.png new file mode 100644 index 0000000000000000000000000000000000000000..313f68de8d63dfb214085770fa47082d9310d3d9 Binary files /dev/null and b/vipra-ui/favicon/mstile-310x150.png differ diff --git a/vipra-ui/favicon/mstile-310x310.png b/vipra-ui/favicon/mstile-310x310.png new file mode 100644 index 0000000000000000000000000000000000000000..59bd91e2e6f1bf335f24980050838a670c37df2b Binary files /dev/null and b/vipra-ui/favicon/mstile-310x310.png differ diff --git a/vipra-ui/favicon/mstile-70x70.png b/vipra-ui/favicon/mstile-70x70.png new file mode 100644 index 0000000000000000000000000000000000000000..bab8744d95ae3da4e74d41dd65c312975443d5e0 Binary files /dev/null and b/vipra-ui/favicon/mstile-70x70.png differ diff --git a/vipra-ui/favicon/safari-pinned-tab.svg b/vipra-ui/favicon/safari-pinned-tab.svg new file mode 100644 index 0000000000000000000000000000000000000000..a4fbb7ddd7e9e63ad948cb3545cc57cdb7b8b66f --- /dev/null +++ b/vipra-ui/favicon/safari-pinned-tab.svg @@ -0,0 +1,43 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<svg version="1.0" xmlns="http://www.w3.org/2000/svg" + width="272.000000pt" height="272.000000pt" viewBox="0 0 272.000000 272.000000" + preserveAspectRatio="xMidYMid meet"> +<metadata> +Created by potrace 1.11, written by Peter Selinger 2001-2013 +</metadata> +<g transform="translate(0.000000,272.000000) scale(0.100000,-0.100000)" +fill="#000000" stroke="none"> +<path d="M78 2334 c18 -21 32 -44 32 -51 0 -7 5 -13 10 -13 6 0 10 -5 10 -11 +0 -6 13 -30 30 -54 17 -24 30 -48 30 -53 0 -6 3 -12 8 -14 9 -4 192 -297 192 +-308 0 -5 3 -10 8 -12 10 -4 62 -86 62 -98 0 -5 4 -10 10 -10 5 0 12 -11 16 +-25 3 -14 10 -25 15 -25 5 0 9 -5 9 -10 0 -6 5 -16 10 -23 32 -37 101 -158 95 +-167 -4 -6 -2 -9 5 -8 6 2 18 -10 28 -27 9 -16 20 -32 23 -35 5 -5 70 -109 +116 -188 12 -20 25 -41 30 -47 5 -5 18 -26 29 -45 10 -19 24 -38 29 -42 7 -5 +7 -8 0 -8 -6 0 -6 -3 0 -8 12 -8 72 -98 101 -152 10 -19 22 -37 25 -40 7 -7 +230 -361 249 -397 8 -15 18 -30 21 -33 3 -3 22 -33 43 -68 21 -34 41 -62 46 +-62 6 0 144 213 200 309 8 14 18 28 22 29 5 2 8 8 8 12 0 9 110 184 130 207 5 +7 10 15 10 19 0 3 18 33 40 66 22 33 40 62 40 65 0 2 23 38 50 80 28 42 50 79 +50 82 0 4 8 16 18 27 9 10 23 30 30 44 7 14 26 45 42 70 16 25 39 61 50 80 11 +19 29 49 40 65 11 17 27 43 36 59 9 16 20 34 25 40 19 23 58 86 53 86 -2 0 4 +9 14 20 10 11 25 33 33 48 7 15 31 54 53 87 21 33 39 66 39 73 0 6 3 12 7 12 +7 0 106 156 111 175 2 6 11 19 21 29 10 11 18 26 18 33 0 7 5 13 10 13 6 0 10 +4 10 10 0 5 20 38 45 73 25 36 45 72 45 81 0 10 5 14 10 11 5 -3 10 -1 10 6 0 +7 10 24 23 38 22 24 22 24 -28 -4 -27 -15 -53 -33 -56 -38 -4 -5 -15 -7 -25 +-3 -10 4 -15 4 -12 0 9 -8 -9 -25 -47 -44 -16 -8 -33 -19 -37 -25 -4 -5 -8 -6 +-8 -1 0 5 -8 2 -18 -6 -9 -9 -35 -26 -57 -38 -81 -45 -260 -155 -263 -162 -2 +-5 -12 -8 -21 -8 -10 0 -26 -9 -36 -20 -10 -11 -24 -20 -32 -20 -7 0 -13 -4 +-13 -8 0 -4 -12 -13 -27 -19 -31 -13 -105 -55 -113 -64 -11 -12 -279 -169 +-288 -169 -6 0 -16 -8 -21 -17 -6 -10 -11 -14 -11 -9 0 6 -7 1 -16 -10 -8 -10 +-13 -13 -9 -6 3 7 -14 -1 -38 -18 -25 -16 -50 -30 -56 -30 -6 0 -11 -4 -11 -8 +0 -5 -11 -14 -25 -20 -23 -11 -41 -3 -198 90 -94 56 -174 105 -177 108 -3 3 +-16 11 -30 18 -14 7 -38 21 -55 32 -54 34 -80 49 -97 56 -10 3 -18 10 -18 15 +0 5 -6 9 -13 9 -7 0 -23 9 -35 20 -12 12 -22 19 -22 16 0 -6 -32 11 -87 47 +-24 15 -47 27 -53 27 -5 0 -10 5 -10 10 0 6 -6 10 -13 10 -7 0 -22 7 -32 15 +-52 41 -134 82 -143 73 -7 -7 -10 -4 -9 8 1 11 -4 18 -10 17 -7 -2 -13 1 -13 +6 0 5 -22 20 -50 32 -27 12 -50 26 -50 30 0 4 -19 16 -42 28 -48 24 -81 43 +-88 52 -3 4 -25 16 -49 29 l-44 22 31 -38z m1816 -532 c3 -5 -1 -9 -9 -9 -8 0 +-12 4 -9 9 3 4 7 8 9 8 2 0 6 -4 9 -8z"/> +</g> +</svg> diff --git a/vipra-ui/gulpfile.js b/vipra-ui/gulpfile.js index 79093a23e0e9d315a8ff3fe6867487dfeb70574a..84c266cf4eedf06a70c04decd3931e34d613701f 100644 --- a/vipra-ui/gulpfile.js +++ b/vipra-ui/gulpfile.js @@ -9,17 +9,17 @@ gulp.task('less', function() { .pipe(sourcemaps.init()) .pipe(less()) .pipe(cssnano()) - .pipe(gulp.dest('css/main.css')); + .pipe(sourcemaps.write()) + .pipe(gulp.dest('css')); }); gulp.task('watch', function() { - gulp.watch('css/**/*.less', ['less']); + gulp.watch('css/app.less', ['less']); }); gulp.task('server', function() { gulp.src('.') .pipe(webserver({ - livereload: true, open: true, port: 4200, fallback: 'index.html' diff --git a/vipra-ui/html/articles/index.html b/vipra-ui/html/articles/index.html new file mode 100644 index 0000000000000000000000000000000000000000..f3476ca851c6080072a12c494aa8af4ff852d82b --- /dev/null +++ b/vipra-ui/html/articles/index.html @@ -0,0 +1,5 @@ +<ul> + <li ng-repeat="article in articles"> + <a ui-sref="articles.show({id: article.id})">{{article.title}}</a> + </li> +</ul> \ No newline at end of file diff --git a/vipra-ui/html/articles/show.html b/vipra-ui/html/articles/show.html new file mode 100644 index 0000000000000000000000000000000000000000..d5b6176cab5ea25d863f6b34364f8ef7cb53e25d --- /dev/null +++ b/vipra-ui/html/articles/show.html @@ -0,0 +1,5 @@ +<h1 ng-bind="article.title"></h1> + +<p ng-bind="article.date"></p> + +<p ng-bind="article.text"></p> \ No newline at end of file diff --git a/vipra-ui/html/index.html b/vipra-ui/html/index.html index 357dd48952bc1b93508f0b0bebb790f09e0730be..45a05c583cade5eda1d5837acabf9310c718ba0c 100644 --- a/vipra-ui/html/index.html +++ b/vipra-ui/html/index.html @@ -1 +1,53 @@ -Home \ No newline at end of file +<div class="container"> + + <div class="row"> + <div class="col-md-12"> + <div class="text-center"> + <h1 class="heading">'vɪprə</h1> + </div> + + <br> + <input type="text" class="form-control input-lg" placeholder="Search..." ng-model="search" ng-model-options="{debounce:500}"> + </div> + </div> + + <br><br> + <div class="row"> + <div class="col-md-6 text-center"> + <h4>Latest articles</h4> + <ul class="list-unstyled"> + <li class="ellipsize" ng-repeat="article in latestArticles"> + <a ui-sref="articles.show({id:article.id})" ng-bind="article.title"></a> + </li> + </ul> + </div> + <div class="col-md-3 text-center"> + <h4>Latest topics</h4> + <ul class="list-unstyled"> + <li class="ellipsize" ng-repeat="topic in latestTopics"> + <a ui-sref="topics.show({id:topic.id})" ng-bind="topic.name"></a> + </li> + </ul> + </div> + <div class="col-md-3 text-center"> + <h4>Latest words</h4> + <ul class="list-unstyled"> + <li class="ellipsize" ng-repeat="word in latestWords"> + <a ui-sref="words.show({id:word.id})" ng-bind="word.id"></a> + </li> + </ul> + </div> + </div> + + <div class="row" ng-show="searchResults.length > 0"> + <hr> + <h4>Results</h4> + <ul class="list-unstyled"> + <li class="search-result" ng-repeat="article in searchResults"> + <a ui-sref="articles.show({id:article.id})" ng-bind="article.title"></a><br> + <p ng-bind="article.text"></p> + </li> + </ul> + </div> + +</div> \ No newline at end of file diff --git a/vipra-ui/html/topics/index.html b/vipra-ui/html/topics/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/vipra-ui/html/topics/show.html b/vipra-ui/html/topics/show.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/vipra-ui/html/words/index.html b/vipra-ui/html/words/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/vipra-ui/html/words/show.html b/vipra-ui/html/words/show.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/vipra-ui/img/logo.png b/vipra-ui/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..76f867cc2335f6b8c77feb78c80504be1cb9387d Binary files /dev/null and b/vipra-ui/img/logo.png differ diff --git a/vipra-ui/index.html b/vipra-ui/index.html index ecf5817a249b9a428015eed532b7958b5eda1612..f1a83eec3051398daeab4b94d094f0f92ddf78f8 100644 --- a/vipra-ui/index.html +++ b/vipra-ui/index.html @@ -1,26 +1,80 @@ <!DOCTYPE html> -<html lang="en" ng-app="vipra"> +<html lang="en" ng-app="vipra.app"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Vipra</title> + <link rel="apple-touch-icon" sizes="57x57" href="/favicon/apple-touch-icon-57x57.png"> + <link rel="apple-touch-icon" sizes="60x60" href="/favicon/apple-touch-icon-60x60.png"> + <link rel="apple-touch-icon" sizes="72x72" href="/favicon/apple-touch-icon-72x72.png"> + <link rel="apple-touch-icon" sizes="76x76" href="/favicon/apple-touch-icon-76x76.png"> + <link rel="apple-touch-icon" sizes="114x114" href="/favicon/apple-touch-icon-114x114.png"> + <link rel="apple-touch-icon" sizes="120x120" href="/favicon/apple-touch-icon-120x120.png"> + <link rel="apple-touch-icon" sizes="144x144" href="/favicon/apple-touch-icon-144x144.png"> + <link rel="apple-touch-icon" sizes="152x152" href="/favicon/apple-touch-icon-152x152.png"> + <link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon-180x180.png"> + <link rel="icon" type="image/png" href="/favicon/favicon-32x32.png" sizes="32x32"> + <link rel="icon" type="image/png" href="/favicon/favicon-194x194.png" sizes="194x194"> + <link rel="icon" type="image/png" href="/favicon/favicon-96x96.png" sizes="96x96"> + <link rel="icon" type="image/png" href="/favicon/android-chrome-192x192.png" sizes="192x192"> + <link rel="icon" type="image/png" href="/favicon/favicon-16x16.png" sizes="16x16"> + <link rel="manifest" href="/favicon/manifest.json"> + <link rel="mask-icon" href="/favicon/safari-pinned-tab.svg" color="#5bbad5"> + <link rel="shortcut icon" href="/favicon/favicon.ico"> + <meta name="msapplication-TileColor" content="#da532c"> + <meta name="msapplication-TileImage" content="/favicon/mstile-144x144.png"> + <meta name="msapplication-config" content="/favicon/browserconfig.xml"> + <meta name="theme-color" content="#ffffff"> + <!-- stylesheets --> <link href="bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"> + <link href="css/app.css" rel="stylesheet"> <!-- javascript --> <script src="bower_components/jquery/dist/jquery.min.js"></script> - <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script> <script src="bower_components/angular/angular.min.js"></script> <script src="bower_components/angular-resource/angular-resource.min.js"></script> <script src="bower_components/angular-ui-router/release/angular-ui-router.min.js"></script> + <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script> <script src="js/app.js"></script> <script src="js/controllers.js"></script> <script src="js/directives.js"></script> + <script src="js/factories.js"></script> <script src="js/services.js"></script> </head> <body> - <div ui-view></div> + <nav class="navbar navbar-default navbar-static-top"> + <div class="container-fluid"> + <!-- Brand and toggle get grouped for better mobile display --> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#vipra-navbar-collapse-1" aria-expanded="false"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a ui-sref="index" class="navbar-brand">vipra</a> + </div> + + <!-- Collect the nav links, forms, and other content for toggling --> + <div class="collapse navbar-collapse" id="vipra-navbar-collapse-1"> + <ul class="nav navbar-nav"> + <li><a ui-sref="articles.index">Articles</a></li> + <li><a ui-sref="topics.index">Topics</a></li> + <li><a ui-sref="words.index">Words</a></li> + <div id="testi"></div> + </ul> + </div><!-- /.navbar-collapse --> + </div><!-- /.container-fluid --> + </nav> + + <div class="container" ui-view></div> + + <footer class="footer navbar-default"> + <div class="container-fluid"> + </div> + </footer> </body> </html> \ No newline at end of file diff --git a/vipra-ui/js/app.js b/vipra-ui/js/app.js index 60d74aac2bde976726600ee6fab20284db6942ec..66b7d3b4936ca75ed3fe66a83055b57f5a9e0063 100644 --- a/vipra-ui/js/app.js +++ b/vipra-ui/js/app.js @@ -1,18 +1,137 @@ -var app = angular.module('vipra', [ - 'ngResource', - 'ui.router', - 'vipra.controllers', - 'vipra.directives', - 'vipra.services' -]); +(function() { -app.config(function($stateProvider, $urlRouterProvider) { + var app = angular.module('vipra.app', [ + 'ngResource', + 'ui.router', + 'vipra.controllers', + 'vipra.directives', + 'vipra.factories', + 'vipra.services' + ]); - $urlRouterProvider.otherwise('/'); + app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) { - $stateProvider.state('index', { - url: '/', - templateUrl: 'html/index.html' - }); + var tplBase = 'html'; -}); \ No newline at end of file + $urlRouterProvider.otherwise('/'); + + // states + + $stateProvider.state('index', { + url: '/', + templateUrl: tplBase + '/index.html', + controller: 'IndexController', + reloadOnSearch: false + }); + + // states: articles + + $stateProvider.state('articles', { + url: '/articles', + abstract: true, + template: '<ui-view/>' + }); + + $stateProvider.state('articles.index', { + url: '', + templateUrl: tplBase + '/articles/index.html', + controller: 'ArticlesIndexController' + }); + + $stateProvider.state('articles.show', { + url: '/:id', + templateUrl: tplBase + '/articles/show.html', + controller: 'ArticlesShowController' + }); + + // states: topics + + $stateProvider.state('topics', { + url: '/topics', + abstract: true, + template: '<ui-view/>' + }); + + $stateProvider.state('topics.index', { + url: '', + templateUrl: tplBase + '/topics/index.html', + controller: 'ArticlesIndexController' + }); + + $stateProvider.state('topics.show', { + url: '/:id', + templateUrl: tplBase + '/topics/show.html', + controller: 'ArticlesShowController' + }); + + // states: words + + $stateProvider.state('words', { + url: '/words', + abstract: true, + template: '<ui-view/>' + }); + + $stateProvider.state('words.index', { + url: '', + templateUrl: tplBase + '/words/index.html', + controller: 'ArticlesIndexController' + }); + + $stateProvider.state('words.show', { + url: '/:id', + templateUrl: tplBase + '/words/show.html', + controller: 'ArticlesShowController' + }); + + }]); + + app.config(['$httpProvider', function($httpProvider) { + + $httpProvider.interceptors.push(function ($q, $injector, $rootScope) { + var requestIncrement = function(config) { + $rootScope.loading.requests = ++$rootScope.loading.requests || 1; + $rootScope.loading[config.method] = ++$rootScope.loading[config.method] || 1; + }; + + var requestDecrement = function(config) { + $rootScope.loading.requests = Math.max(--$rootScope.loading.requests, 0); + $rootScope.loading[config.method] = Math.max(--$rootScope.loading[config.method], 0); + }; + + return { + request: function(config) { + requestIncrement(config); + return config; + }, + + requestError: function(rejection) { + requestDecrement(rejection.config); + return $q.reject(rejection); + }, + + response: function(response) { + requestDecrement(response.config); + return response; + }, + + responseError: function(rejection) { + requestDecrement(rejection.config); + return $q.reject(rejection); + } + }; + }); + + }]); + + app.run(['$rootScope', function($rootScope) { + + $rootScope.loading = {}; + + $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) { + console.log('changing state: ' + toState.name); + }); + + }]); + +})(); \ No newline at end of file diff --git a/vipra-ui/js/controllers.js b/vipra-ui/js/controllers.js index 63b99a10c99c34ed7b8889295aacd0c68f2a0612..42300697efa7050097dd57b92a41d8007ab424cd 100644 --- a/vipra-ui/js/controllers.js +++ b/vipra-ui/js/controllers.js @@ -1,5 +1,48 @@ -var app = angular.module('vipra.controllers', []); +(function() { -app.controller('MainCtrl', function($scope) { + var app = angular.module('vipra.controllers', [ + 'ui.router', + 'vipra.factories' + ]); -}); \ No newline at end of file + app.controller('IndexController', ['$scope', '$location', 'ArticleFactory', 'TopicFactory', 'WordFactory', 'SearchFactory',function($scope, $location, ArticleFactory, TopicFactory, WordFactory, SearchFactory) { + $scope.search = $location.search().query; + + ArticleFactory.query({limit:3, sort:'-created'}, function(response) { + $scope.latestArticles = response.data; + }); + + TopicFactory.query({limit:3, sort:'-created'}, function(response) { + $scope.latestTopics = response.data; + }); + + WordFactory.query({limit:3, sort:'-created'}, function(response) { + $scope.latestWords = response.data; + }); + + $scope.$watch('search', function() { + if($scope.search) { + $location.search('query', $scope.search); + SearchFactory.query({limit:10, query:$scope.search}, function(response) { + $scope.searchResults = response.data; + }); + } else { + $location.search('query', null); + $scope.searchResults = []; + } + }); + }]); + + app.controller('ArticlesIndexController', ['$scope', 'ArticleFactory', function($scope, ArticleFactory) { + ArticleFactory.query(function(response) { + $scope.articles = response.data; + }); + }]); + + app.controller('ArticlesShowController', ['$scope', '$stateParams', 'ArticleFactory', function($scope, $stateParams, ArticleFactory) { + ArticleFactory.get({id: $stateParams.id}, function(response) { + $scope.article = response.data; + }); + }]); + +})(); \ No newline at end of file diff --git a/vipra-ui/js/directives.js b/vipra-ui/js/directives.js index 07291e39bee63c79e85193bef7729ef3083687b9..05b64aefd11b6771f2b6e9194caec1710896db86 100644 --- a/vipra-ui/js/directives.js +++ b/vipra-ui/js/directives.js @@ -1 +1,5 @@ -var app = angular.module('vipra.directives', []); \ No newline at end of file +(function() { + + var app = angular.module('vipra.directives', []); + +})(); \ No newline at end of file diff --git a/vipra-ui/js/factories.js b/vipra-ui/js/factories.js new file mode 100644 index 0000000000000000000000000000000000000000..62564fd739a65b6d70cf4898c80ad5fbd2674c7f --- /dev/null +++ b/vipra-ui/js/factories.js @@ -0,0 +1,31 @@ +(function() { + + var app = angular.module('vipra.factories', []); + + var endpoint = '//' + location.hostname + ':8000'; + + app.factory('ArticleFactory', ['$resource', function($resource) { + return $resource(endpoint + '/vipra-rest/articles/:id', {}, { + query: { isArray: false } + }); + }]); + + app.factory('TopicFactory', ['$resource', function($resource) { + return $resource(endpoint + '/vipra-rest/topics/:id', {}, { + query: { isArray: false } + }); + }]); + + app.factory('WordFactory', ['$resource', function($resource) { + return $resource(endpoint + '/vipra-rest/words/:id', {}, { + query: { isArray: false } + }); + }]); + + app.factory('SearchFactory', ['$resource', function($resource) { + return $resource(endpoint + '/vipra-rest/search', {}, { + query: { isArray: false } + }); + }]); + +})(); \ No newline at end of file diff --git a/vipra-ui/js/services.js b/vipra-ui/js/services.js index 998e2cefe83939d8e5e3de9f5383fcac6cdf23cc..cc05f9e1c0d8c72892ecbc564480f283451a7a58 100644 --- a/vipra-ui/js/services.js +++ b/vipra-ui/js/services.js @@ -1 +1,5 @@ -var app = angular.module('vipra.services', []); \ No newline at end of file +(function() { + + var app = angular.module('vipra.services', []); + +})(); \ No newline at end of file diff --git a/vipra-ui/package.json b/vipra-ui/package.json index 1b966c29474c3e17500c4b36b4cf0312585b6153..330c6ea849b29a919ba5e850c676cf886092d808 100644 --- a/vipra-ui/package.json +++ b/vipra-ui/package.json @@ -7,6 +7,7 @@ "devDependencies": { "gulp": "^3.9.0", "gulp-cssnano": "^2.1.0", + "gulp-include": "^2.1.0", "gulp-less": "^3.0.5", "gulp-sourcemaps": "^1.6.0", "gulp-webserver": "^0.9.1"