scala-news-reader
rss/atom news reader in scala
git clone https://9o.is/git/scala-news-reader.git
commit 42d6570915ea5253b4c9658795254e1722b74bfe parent 47ab6ae8a56ec61efa4d8a6c0dab7d62115f9e8d Author: Jul <jul@9o.is> Date: Sun, 4 Aug 2013 09:01:02 -0400 Can now view shared articles. Diffstat:
| M | src/main/less/styles.less | | | 12 | +++++++++--- |
| M | src/main/scala/com/joereader/model/User.scala | | | 44 | ++++++++++++++++++++++---------------------- |
| M | src/main/scala/com/joereader/snippet/ArticleSnip.scala | | | 96 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
| M | src/main/scala/com/joereader/snippet/BlogSnipView.scala | | | 2 | +- |
| M | src/main/scala/com/joereader/snippet/BlogWriterSnipView.scala | | | 2 | +- |
| M | src/main/scala/com/joereader/snippet/MyBlog.scala | | | 2 | +- |
| M | src/main/scala/com/joereader/snippet/ReaderSnip.scala | | | 47 | +++++++++++++++++++++++++++++++++++++++++------ |
| M | src/main/scala/com/joereader/snippet/UserWriterSnipView.scala | | | 38 | ++++++++++++++++++++++++++++++++++---- |
| M | src/main/webapp/blogwriter.html | | | 183 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
| M | src/main/webapp/index.html | | | 350 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
| M | src/main/webapp/reader.html | | | 195 | +++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
| M | src/main/webapp/saved.html | | | 132 | ++++++++++++++++++++++++++++++++++++++++---------------------------------------- |
| M | src/main/webapp/templates-hidden/parts/blog-profile.html | | | 8 | +++++++- |
| M | src/main/webapp/templates-hidden/parts/user-profile.html | | | 8 | +++++++- |
14 files changed, 640 insertions(+), 479 deletions(-)
diff --git a/src/main/less/styles.less b/src/main/less/styles.less @@ -865,9 +865,15 @@ body { .sub-header { color: @grayLight; font-size: @fontSizeSmall; - padding-top: @lineHeightArticle * 8px; // line height is em - padding-bottom: @lineHeightArticle * 8px; // line height is em - * { + padding-top: @lineHeightArticle * 20px; // line height is em + padding-bottom: @lineHeightArticle * 10px; // line height is em + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + .article-sharedby { color: @grayLight } + .article-sharedby-img { .border-radius(50%); width: 25px; height: 25px; } + .right-sub-header * { margin-left: 15px; float:right; } diff --git a/src/main/scala/com/joereader/model/User.scala b/src/main/scala/com/joereader/model/User.scala @@ -6,7 +6,7 @@ import org.bson.types._ import net.liftweb._ import util._ import common._ -import http.{StringField => _, BooleanField => _, _} +import http.{ StringField => _, BooleanField => _, _ } import mongodb.record._, field._ import record.field._ @@ -15,10 +15,11 @@ import net.liftmodules.mongoauth._, model._ import com.joereader._ import config._ import snippet._ +import lib.rss._ import net.liftweb.common.Full -class User private() extends ProtoAuthUser[User] with ObjectIdPk[User] { +class User private () extends ProtoAuthUser[User] with ObjectIdPk[User] { def meta = User def userIdAsString: String = id.toString() @@ -55,7 +56,6 @@ class User private() extends ProtoAuthUser[User] with ObjectIdPk[User] { def removeBlog(blog: Blog) = blogs(blogs.get.filterNot(_ == blog.id.get)) - /* Contains a list of blog id to writer name separated by separator. */ object following extends MongoListField[User, String](this) { @@ -68,7 +68,7 @@ class User private() extends ProtoAuthUser[User] with ObjectIdPk[User] { if (who == "sa") for (user <- User.findByStringId(id)) - yield BlogWriterUser(Some(user)) + yield BlogWriterUser(Some(user)) else for { @@ -86,13 +86,18 @@ class User private() extends ProtoAuthUser[User] with ObjectIdPk[User] { val random = Seq.fill(n)(scala.util.Random.nextInt(get.size)).distinct random.map(user).flatten - } - else Nil + } else Nil } def allUsers: List[BlogWriterUser] = uniqueOnly((0 until get.size).map(user).flatten) + def usersSharedArticles: List[User] = + (0 until get.size).map { i => + val who = get(i).split(separator).tail.mkString + if(who == "sa") user(i).map(_.user) else Empty + }.flatten.flatten.toList + def exists(bw: BlogWriter, blog: Blog): Boolean = get.exists(_ == create(bw, blog)) @@ -146,8 +151,7 @@ class User private() extends ProtoAuthUser[User] with ObjectIdPk[User] { blogs <- blogs.get blog <- Blog.find(blogs) writer <- blog.writer(this) - } yield - writer.followers.get.map(_.toString)).flatten + } yield writer.followers.get.map(_.toString)).flatten val sharedArticlesFollowers: List[String] = followers.get.map(_.toString) @@ -156,7 +160,7 @@ class User private() extends ProtoAuthUser[User] with ObjectIdPk[User] { } object saved extends MongoListField[User, String](this) - + def saveArticle(article: Article) = { if (saved.get.exists(_ == article.id)) this else saved(article.id :: saved.get) @@ -164,15 +168,15 @@ class User private() extends ProtoAuthUser[User] with ObjectIdPk[User] { def unSaveArticle(article: Article) = saved(saved.get.filterNot(_ == article.id)) - + object shared extends MongoListField[User, String](this) - - def shareArticle(article: Article) = { + + def shareArticle(article: SharedArticle) = { if (shared.get.exists(_ == article.id)) this else shared(article.id :: shared.get) } - def unShareArticle(article: Article) = + def unShareArticle(article: SharedArticle) = shared(shared.get.filterNot(_ == article.id)) } @@ -209,8 +213,7 @@ object User extends User with ProtoAuthUserMeta[User] with Loggable { boxedUser => boxedUser.foreach { u => ExtSession.deleteExtCookie() - } - ) + }) /* * MongoAuth vars @@ -238,8 +241,7 @@ object User extends User with ProtoAuthUserMeta[User] with Loggable { logUserIn(user) //at.delete_! (token is deleted at Password Reset) RedirectResponse(loginTokenAfterUrl) - } - else { + } else { at.delete_! regUser(user) RedirectWithState(registerUrl, RedirectState(() => { @@ -281,8 +283,7 @@ object User extends User with ProtoAuthUserMeta[User] with Loggable { From(MongoAuth.systemFancyEmail), Subject("%s Password Help".format(siteName)), To(user.fancyEmail), - PlainMailBodyType(msgTxt) - ) + PlainMailBodyType(msgTxt)) } def handleInviteToken(): Box[LiftResponse] = { @@ -365,15 +366,14 @@ object User extends User with ProtoAuthUserMeta[User] with Loggable { |%s """. format(name, user.name.get, blog.name.get, token.url, - MongoAuth.systemUsername.vend).stripMargin + MongoAuth.systemUsername.vend).stripMargin sendMail( From(MongoAuth.systemFancyEmail), Subject("%s invites you to %s". format(user.name.get, MongoAuth.siteName.vend)), To(email), - PlainMailBodyType(msgTxt) - ) + PlainMailBodyType(msgTxt)) } // used during login process (holds email address) diff --git a/src/main/scala/com/joereader/snippet/ArticleSnip.scala b/src/main/scala/com/joereader/snippet/ArticleSnip.scala @@ -9,41 +9,42 @@ import util._ import Helpers._ import com.joereader._ +import config._ import lib.rss._ import model._ import xml._ +import java.util.Date /** * Mix this in to list articles. */ trait ArticleSnip { - def sort(entries: List[(FeedEntry, BlogWriterUser)]) = - entries.sortWith((x,y) => x._1.date.getTime > y._1.date.getTime) + def sort(entries: List[Article]) = + entries.sortWith((x,y) => x.date.getTime > y.date.getTime) - def articles(entries: List[(FeedEntry, BlogWriterUser)]): CssSel = - if(entries.isEmpty) + def articles(articles: List[Article]): CssSel = + if(articles.isEmpty) ".reader-nav [class+]" #> "hide" & ".article *" #> <p style="padding: 200px 0; text-align: center"> No articles to display here </p> - else ".article *" #> sort(entries).map { - f => - val (entry, bwu) = f - - def article = bwu.blog.map(Article(_, entry)) - def articleId = article.map(_.id).getOrElse("") - def shareId = article.map(_.idHash+"-share").getOrElse("") - def saveId = article.map(_.idHash+"-save").getOrElse("") + else ".article *" #> sort(articles).map { + article => + + def bwu = article.bwu + def entry = article.entry + def shareId = article.id.hashCode+"-share" + def saveId = article.id.hashCode+"-save" def color = "color:" + bwu.color def saved: Boolean = User.currentUser.exists( - _.saved.get.exists(_ == articleId)) + _.saved.get.exists(_ == article.id)) def shared: Boolean = User.currentUser.exists( - _.shared.get.exists(_ == articleId)) + _.shared.get.exists(_ == article.id)) def saveLink: NodeSeq = a(() => save, Text("Save"), "id" -> saveId, "style" -> color) @@ -58,32 +59,38 @@ trait ArticleSnip { a(() => unShare, Text("Undo Share"), "id" -> shareId, "style" -> color) def save: JsCmd = { - for (u <- User.currentUser; a <- article) - u.saveArticle(a).update + for (u <- User.currentUser) + u.saveArticle(article).update Replace(saveId, unSaveLink) } def unSave: JsCmd = { - for (u <- User.currentUser; a <- article) - u.unSaveArticle(a).update + for (u <- User.currentUser) + u.unSaveArticle(article).update Replace(saveId, saveLink) } def share: JsCmd = { - for (u <- User.currentUser; a <- article) - u.shareArticle(a).update + for (u <- User.currentUser) { + val sa = new SharedArticle(bwu, entry, u, new Date) + u.shareArticle(sa).update + } Replace(shareId, unShareLink) } def unShare: JsCmd = { - for (u <- User.currentUser; a <- article) - u.unShareArticle(a).update + for (u <- User.currentUser) + u.unShareArticle(article.asInstanceOf[SharedArticle]).update Replace(shareId, shareLink) } - ".article-save" #> (if (saved) unSaveLink else saveLink) & - ".article-share" #> (if (shared) unShareLink else shareLink) & + ".article-save" #> (if(User.isLoggedIn) {if (saved) unSaveLink else saveLink} else NodeSeq.Empty) & + ".article-share" #> (if(User.isLoggedIn) {if (shared) unShareLink else shareLink} else NodeSeq.Empty) & ".article-inner [style]" #> ("border-right:3px solid " + bwu.color) & + ".left-sub-header-inner [class+]" #> (if(article.sharedBy.isDefined) "" else "hide") & + ".article-sharedby *" #> article.sharedBy.map(_.name.get) & + ".article-sharedby [href]" #> article.sharedBy.map(Site.userProfileLoc.calcHref) & + ".article-sharedby-img [src]" #> BlogWriterUser(article.sharedBy).image & ".article-key [class+]" #> bwu.id & ".article-user-link [href]" #> bwu.link & "#article-user-image [src]" #> bwu.image & @@ -95,7 +102,7 @@ trait ArticleSnip { "#article-content" #> entry.content } & "#reader-writers" #> { - "#writer" #> entries.distinct.groupBy(_._2).map { + "#writer" #> articles.distinct.groupBy(_.bwu).map { f => val bwu = f._1 @@ -108,13 +115,44 @@ trait ArticleSnip { } -object Article { +trait ArticleTrait { def separator = "~" + def createId(blog: Blog, entry: FeedEntry) = + blog.id.get + separator + entry.id +} + +object Article extends ArticleTrait + +object SharedArticle extends ArticleTrait { + def createId(blog: Blog, entry: FeedEntry, date: Date) = + super.createId(blog, entry) + separator + date.getTime +} + +class Article(_bwu: BlogWriterUser, _entry: FeedEntry) { + + def id: String = + bwu.blog.map(Article.createId(_, entry)). + getOrElse("") + + def date: Date = entry.date + def entry = _entry + def bwu = _bwu + + val sharedBy: Option[User] = None } -case class Article(blog: Blog, entry: FeedEntry) { - def id: String = blog.id.get + Article.separator + entry.id - def idHash = id.hashCode +class SharedArticle( + bwu: BlogWriterUser, + entry: FeedEntry, + _sharedBy: User, + sharedDate: Date = new Date) extends Article(bwu, entry) { + + override def date = sharedDate + override def id = + bwu.blog.map(SharedArticle.createId(_, entry, date)). + getOrElse("") + + override val sharedBy = Some(_sharedBy) } diff --git a/src/main/scala/com/joereader/snippet/BlogSnipView.scala b/src/main/scala/com/joereader/snippet/BlogSnipView.scala @@ -60,7 +60,7 @@ trait BlogSnipView extends BlogSnip with ArticleSnip with BackgroundSnip { val blogWriter: Box[BlogWriter] = blog.writer(entry.author.name) val bwu = BlogWriterUser( blogWriter.flatMap(_.user.obj), Some(blog), blogWriter) - (entry, bwu) + new Article(bwu, entry) } articles(entries) diff --git a/src/main/scala/com/joereader/snippet/BlogWriterSnipView.scala b/src/main/scala/com/joereader/snippet/BlogWriterSnipView.scala @@ -20,7 +20,7 @@ trait BlogWriterSnipView extends BlogWriterUserSnip with ArticleSnip with Backgr val entries = blog.urlRss.get.head.entries. filter(_.author.name == blogWriter.name.get). - map((_, BlogWriterUser(None, Some(blog), Some(blogWriter)))) + map(new Article(BlogWriterUser(None, Some(blog), Some(blogWriter)), _)) articles(entries) diff --git a/src/main/scala/com/joereader/snippet/MyBlog.scala b/src/main/scala/com/joereader/snippet/MyBlog.scala @@ -33,7 +33,7 @@ class MyBlog extends BlogSnip with ArticleSnip { val blogWriter: Box[BlogWriter] = blog.writer(entry.author.name) val bwu = BlogWriterUser( blogWriter.flatMap(_.user.obj), Some(blog), blogWriter) - (entry, bwu) + new Article(bwu, entry) } articles(entry.toList) diff --git a/src/main/scala/com/joereader/snippet/ReaderSnip.scala b/src/main/scala/com/joereader/snippet/ReaderSnip.scala @@ -3,12 +3,14 @@ package com.joereader.snippet import net.liftweb._ import common._ import http._ +import util.Helpers._ import com.joereader._ import model._ import lib.rss._ import scala.xml._ +import java.util.Date /** * View all of your articles. @@ -19,23 +21,56 @@ class ReaderSnip extends UserSnip with ArticleSnip { def articles(html: NodeSeq): NodeSeq = serve(html) { user => - val entries: List[(FeedEntry, BlogWriterUser)] = + val articlesFollowing: List[Article] = user.following.allUsers.flatMap(bwu => for { blog <- bwu.blog blogWriter <- bwu.blogWriter } yield blog.urlRss.get.head.entries. filter(_.author.name == blogWriter.name.get.toString). - map((_, bwu))).flatten + map(new Article(bwu, _))).flatten + + val articlesShared: List[Article] = { + user.following.usersSharedArticles.flatMap { user => + + val blogIds: List[String] = + user.shared.get.flatMap(str => + str.split(Article.separator).headOption).distinct + + val blogs: List[Blog] = + blogIds.flatMap(Blog.findByStringId) + + val allEntries: List[(Blog, List[FeedEntry])] = + blogs.map(b => (b, b.urlRss.get.head.entries)).toList + + val sharedEntries: List[(Blog, List[FeedEntry])] = + allEntries.map(f => + (f._1, f._2.filter { e => + user.shared.get.exists(_.startsWith(Article.createId(f._1, e))) + })).filterNot(_._2.isEmpty) + + sharedEntries.flatMap(f => + f._2.map { entry => + val id = user.shared.get.find(_.startsWith(Article.createId(f._1, entry))) + val time = id.map(_.split(SharedArticle.separator).last) + val date: Option[Date] = tryo(time.map(t => new Date(t.toLong))).openOr(None) + + val blog = Some(f._1) + val blogWriter = f._1.writer(entry.author.name) + val u = blogWriter.flatMap(_.user.obj) + new SharedArticle(BlogWriterUser(u, blog, blogWriter), entry, user, date.getOrElse(entry.date)) + }) + } + } - articles(entries) + articles(articlesFollowing ::: articlesShared) }(TestUser.isLoggedIn, NodeSeq.Empty) def savedArticles(html: NodeSeq): NodeSeq = serve(html) { user => - def entries: List[(FeedEntry, BlogWriterUser)] = { + def entries: List[Article] = { val blogIds: List[String] = user.saved.get.flatMap(str => str.split(Article.separator).headOption) @@ -49,14 +84,14 @@ class ReaderSnip extends UserSnip with ArticleSnip { val savedEntries: List[(Blog, List[FeedEntry])] = allEntries.map(f => (f._1, f._2.filter(e => user.saved.get. - exists(_ == Article(f._1, e).id)))).filterNot(_._2.isEmpty) + exists(_ == Article.createId(f._1, e))))).filterNot(_._2.isEmpty) savedEntries.flatMap(f => f._2.map { entry => val blog = Some(f._1) val blogWriter = f._1.writer(entry.author.name) val user = blogWriter.flatMap(_.user.obj) - (entry, BlogWriterUser(user, blog, blogWriter)) + new Article(BlogWriterUser(user, blog, blogWriter), entry) }) } diff --git a/src/main/scala/com/joereader/snippet/UserWriterSnipView.scala b/src/main/scala/com/joereader/snippet/UserWriterSnipView.scala @@ -2,6 +2,7 @@ package com.joereader.snippet import net.liftweb.util.Helpers._ import scala.xml._ +import java.util.Date import com.joereader._ import config._ @@ -54,17 +55,46 @@ trait UserWriterSnipView extends UserSnip with ArticleSnip with BackgroundSnip { def articles(html: NodeSeq): NodeSeq = serve(html) { user => - val entries: List[(FeedEntry, BlogWriterUser)] = + val entries: List[Article] = (for { blogs <- user.blogs.get blog <- Blog.find(blogs) blogWriter <- blog.writer(user) } yield blog.urlRss.get.head.entries. filter(_.author.name == blogWriter.name.get). - map((_, BlogWriterUser(Some(user), Some(blog), Some(blogWriter))))). + map(new Article(BlogWriterUser(Some(user), Some(blog), Some(blogWriter)), _))). flatten - - articles(entries) + + val sharedEntries: List[SharedArticle] = { + val blogIds: List[String] = + user.shared.get.flatMap(str => + str.split(Article.separator).headOption).distinct + + val blogs: List[Blog] = + blogIds.flatMap(Blog.findByStringId) + + val allEntries: List[(Blog, List[FeedEntry])] = + blogs.map(b => (b, b.urlRss.get.head.entries)).toList + + val sharedEntries: List[(Blog, List[FeedEntry])] = + allEntries.map(f => + (f._1, f._2.filter { e => + user.shared.get.exists(_.startsWith(Article.createId(f._1, e))) + })).filterNot(_._2.isEmpty) + + sharedEntries.flatMap(f => + f._2.map { entry => + val id = user.shared.get.find(_.startsWith(Article.createId(f._1, entry))) + val time = id.map(_.split(SharedArticle.separator).last) + val date: Option[Date] = tryo(time.map(t => new Date(t.toLong))).openOr(None) + + val blog = Some(f._1) + val blogWriter = f._1.writer(entry.author.name) + val u = blogWriter.flatMap(_.user.obj) + new SharedArticle(BlogWriterUser(u, blog, blogWriter), entry, user, date.getOrElse(entry.date)) + }) + } + articles(entries ::: sharedEntries) }(test, NodeSeq.Empty) diff --git a/src/main/webapp/blogwriter.html b/src/main/webapp/blogwriter.html @@ -1,103 +1,110 @@ -<div data-lift="surround?with=base-wrap;at=content" xmlns:lift="http://www.w3.org/1999/xhtml"> - <lift:head> - <title data-lift="Menu.title">Read Means: %*%</title> - </lift:head> +<div data-lift="surround?with=base-wrap;at=content" + xmlns:lift="http://www.w3.org/1999/xhtml"> + <lift:head> + <title data-lift="Menu.title">Read Means: %*%</title> + </lift:head> - <div id="profile-wrap"> + <div id="profile-wrap"> - <div id="bg"> - <img data-lift="ProfileLocBlogWriter.bgImg" /> - </div> + <div id="bg"> + <img data-lift="ProfileLocBlogWriter.bgImg" /> + </div> - <div class="boxed-articles"> - <div id="profile"> + <div class="boxed-articles"> + <div id="profile"> - <div class="row-fluid"> - <div id="profile-img" class="span12 text-center"> - <img data-lift="ProfileLocBlogWriter.img"> - </div> - </div> + <div class="row-fluid"> + <div id="profile-img" class="span12 text-center"> + <img data-lift="ProfileLocBlogWriter.img"> + </div> + </div> - <div id="profile-inner"> + <div id="profile-inner"> - <div class="row-fluid"> - <div id="user-name" class="span12 text-center up-separate"> - <span data-lift="ProfileLocBlogWriter.name"></span> - </div> - </div> + <div class="row-fluid"> + <div id="user-name" class="span12 text-center up-separate"> + <span data-lift="ProfileLocBlogWriter.name"></span> + </div> + </div> - <div class="row-fluid"> - <div data-lift="ProfileLocBlogWriter.url" id="blog-url" class="span12 text-center nolink-decoration"> - <a href=""></a> - </div> - </div> + <div class="row-fluid"> + <div data-lift="ProfileLocBlogWriter.url" id="blog-url" + class="span12 text-center nolink-decoration"> + <a href=""></a> + </div> + </div> - <div class="row-fluid" data-lift="TestCond.loggedin"> - <div class="span12 text-center up-separate"> - <div id="follow-btn-wrapper"> - <span data-lift="ProfileLocBlogWriter.followButton"></span> - </div> - <div id="following-amount"> - <span data-lift="ProfileLocBlogWriter.followersAmount"></span> - </div> - </div> - </div> + <div class="row-fluid" data-lift="TestCond.loggedin"> + <div class="span12 text-center up-separate"> + <div id="follow-btn-wrapper"> + <span data-lift="ProfileLocBlogWriter.followButton"></span> + </div> + <div id="following-amount"> + <span data-lift="ProfileLocBlogWriter.followersAmount"></span> + </div> + </div> + </div> - </div> - </div> - </div> + </div> + </div> + </div> - <div id="profile-articles-area"> - <div class="container"> - <div data-lift="ProfileLocBlogWriter.articles" class="row-fluid"> + <div id="profile-articles-area"> + <div class="container"> + <div data-lift="ProfileLocBlogWriter.articles" class="row-fluid"> - <div id="reader-nav-wrapper" class="span2 offset0"> - <div class="reader-nav-blog reader-nav reader-span-spacing nolink-decoration"> - <ul id="reader-writers" class="nav text-center"> - <li id="writer"> - <a href=""> - <img id="writer-image" src="" /> - </a> - <a id="writer-name" href=""></a> - </li> - </ul> - </div> - </div> + <div id="reader-nav-wrapper" class="span2 offset0"> + <div + class="reader-nav-blog reader-nav reader-span-spacing nolink-decoration"> + <ul id="reader-writers" class="nav text-center"> + <li id="writer"><a href=""> <img id="writer-image" + src="" /> + </a> <a id="writer-name" href=""></a></li> + </ul> + </div> + </div> - <div id="boxed-articles-wrapper" class="span8 offset0"> - <div class="boxed-articles boxed-articles-span"> - <div class="article keynav-article"> - <div class="article-inner"> - <div class="article-key"></div> - <div class="row-fluid header text-center"> - <div class="span12"> - <a class="article-user-link" href=""> - <img id="article-user-image" src=""/> - </a> - <div class="writer-name nolink-decoration"> - <a id="article-user-name" class="article-user-link" href=""></a> - </div> - </div> - </div> - <div class="title"> - <a href="" target="_blank"></a> - </div> - <div class="row-fluid sub-header"> - <div class="span12"> - <time class="timeago" datetime=""></time> - <span class="article-share"></span> - <span class="article-save"></span> - </div> - </div> - <span id="article-content"></span> - </div> - </div> - </div> - </div> + <div id="boxed-articles-wrapper" class="span8 offset0"> + <div class="boxed-articles boxed-articles-span"> + <div class="article keynav-article"> + <div class="article-inner"> + <div class="article-key"></div> + <div class="row-fluid header text-center"> + <div class="span12"> + <a class="article-user-link" href=""> <img + id="article-user-image" src="" /> + </a> + <div class="writer-name nolink-decoration"> + <a id="article-user-name" class="article-user-link" href=""></a> + </div> + </div> + </div> + <div class="title"> + <a href="" target="_blank"></a> + </div> + <div class="row-fluid sub-header"> + <div class="span4 left-sub-header"> + <div class="left-sub-header-inner"> + <img src="" class="article-sharedby-img" /> <span>Shared + by <a class="article-sharedby"></a> + </span> + </div> + </div> + <div class="span8 right-sub-header"> + <time class="timeago" datetime=""></time> + <span class="article-share"></span> <span + class="article-save"></span> + </div> + </div> + <span id="article-content"></span> + </div> + </div> + </div> + </div> - </div> - </div> - </div> + </div> + </div> + </div> - </div> + </div> </div> \ No newline at end of file diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html @@ -1,162 +1,190 @@ -<div data-lift="surround?with=base-wrap;at=content" xmlns:lift="http://www.w3.org/1999/xhtml"> - - <lift:head> - <title data-lift="Menu.title">Read Means: %*%</title> - </lift:head> - - <div id="top-index-bg"></div> - - <div class="container"> - - <div class="row-fluid features"> - - <div class="span8 offset0"> - - <div class="row-fluid"> - <div class="span12 offset0 marketing content" style="background-color:#fff"> - Improve your reading experience - <div class="small" style="font-weight: normal; margin-top: 10px">Discover and follow blog writers with the friendliest rss reader!</div> - <div class="logo" style="margin-top:20px"> - <span class="readBlue">Read</span> - <span class="readOrange"> means</span> - </div> - </div> - </div> - - <div class="row-fluid"> - - <div class="span6 offset0"> - - <div class="row-fluid"> - <div class="span12 offset0 content" style="background-color:#1E7697; color: #fff"> - <div class="text">Discover blog writers by your favorite categories.</div> - <img src="/img/features/categories.jpg" alt="Search by categories" /> - </div> - </div> - - <div class="row-fluid"> - <div class="span12 offset0 content" style="background-color:#FDA348; color: #fff"> - <div class="text">Save and share articles with your Facebook, Twitter and Read Means friends</div> - <img src="/img/features/share-laptop1.jpg" alt="Share and Save articles" /> - </div> - </div> - - </div> - - <div class="span6 offset0"> - - <div class="row-fluid"> - <div class="span12 offset0 content" style="background-color:#84D5F4; color: #fff; height: 700px"> - <div class="text">Follow blog writers and view all their articles plus the writers they follow.</div> - <img src="/img/features/profile-phone.jpg" alt="Follow blog writers and view who they follow." /> - </div> - </div> - - </div> - - </div> - - <div class="row-fluid"> - <div class="span12 offset0 content" style="background-color:#f1eee0; color: #666"> - <div class="row-fluid"> - <div class="span4"> - <div class="text">Watch a quick 30 seconds intro video about the writer's purpose.</div> - </div> - <div class="span8"> - <img src="/img/features/video1.jpg" alt="Watch quick videos" /> - </div> - </div> - - </div> - </div> - - </div> - - - <div class="span4 offset0"> - - <div class="row-fluid"> - <div class="span12 offset0 content" style="background-color:#FB840B; color:#fff; height: 700px"> - <div class="text">Beautiful. Casual. Simple. Clean. Fun.</div> - <img src="/img/features/reader-ipad.jpg" alt="Simple. Casual. Simple. Clean. Fun." /> - </div> - </div> - - <div class="row-fluid"> - <div class="span12 offset0 content" style="background-color:#00c7e1; color: #fff; height: 700px"> - <div class="text">Explore a category and preview 8 chosen writers</div> - <img src="/img/features/writers-8.jpg" alt="Explore writers by category." /> - </div> - </div> - - </div> - - </div> - - <div data-lift="MyBlog.entry" class="row-fluid" style="margin:100px 0"> - <h1 style="margin:50px 0">Latest Blog Post</h1> - <div id="reader-nav-wrapper" class="span2 offset0"> - <div class="reader-nav-blog reader-nav reader-span-spacing nolink-decoration"> - <ul id="reader-writers" class="nav text-center"> - <li id="writer"> - <a href=""> - <img id="writer-image" src="" /> - </a> - <a id="writer-name" href=""></a> - </li> - </ul> - - </div> - </div> - - <div id="boxed-articles-wrapper" class="span8 offset0"> - <div class="boxed-articles boxed-articles-span"> - <div class="article keynav-article"> - <div class="article-inner"> - <div class="article-key"></div> - <div class="row-fluid header text-center"> - <div class="span12"> - <a class="article-user-link" href=""> - <img id="article-user-image" src=""/> - </a> - <div class="writer-name nolink-decoration"> - <a id="article-user-name" class="article-user-link" href=""></a> - </div> - </div> - </div> - <div class="title"> - <a href="" target="_blank"></a> - </div> - <div class="row-fluid sub-header"> - <div class="span12"> - <time class="timeago" datetime=""></time> - </div> - </div> - <span id="article-content"></span> - </div> - </div> - </div> - </div> - </div> - - </div> - - <div data-lift="ignore"> - <div id="writerswelove"></div> - <div class="container"> - <div class="articles"> - <div class="article text-center"> - <h2>Writers we Love</h2> - <p>In Read Means, writers are celebrities because we believe writers create content, not content creates writers. Check out our featured writers that you can follow with - <span class="readBlue">Read</span><span class="readOrange"> means</span> - </p> - </div> - </div> - </div> - <span data-lift="embed?what=/templates-hidden/parts/writers-gallery"></span> - </div> - - - - <span data-lift="embed?what=/templates-hidden/parts/footer"></span> +<div data-lift="surround?with=base-wrap;at=content" + xmlns:lift="http://www.w3.org/1999/xhtml"> + + <lift:head> + <title data-lift="Menu.title">Read Means: %*%</title> + </lift:head> + + <div id="top-index-bg"></div> + + <div class="container"> + + <div class="row-fluid features"> + + <div class="span8 offset0"> + + <div class="row-fluid"> + <div class="span12 offset0 marketing content" + style="background-color: #fff"> + Improve your reading experience + <div class="small" style="font-weight: normal; margin-top: 10px">Discover + and follow blog writers with the friendliest rss reader!</div> + <div class="logo" style="margin-top: 20px"> + <span class="readBlue">Read</span> <span class="readOrange"> + means</span> + </div> + </div> + </div> + + <div class="row-fluid"> + + <div class="span6 offset0"> + + <div class="row-fluid"> + <div class="span12 offset0 content" + style="background-color: #1E7697; color: #fff"> + <div class="text">Discover blog writers by your favorite + categories.</div> + <img src="/img/features/categories.jpg" + alt="Search by categories" /> + </div> + </div> + + <div class="row-fluid"> + <div class="span12 offset0 content" + style="background-color: #FDA348; color: #fff"> + <div class="text">Save and share articles with your + Facebook, Twitter and Read Means friends</div> + <img src="/img/features/share-laptop1.jpg" + alt="Share and Save articles" /> + </div> + </div> + + </div> + + <div class="span6 offset0"> + + <div class="row-fluid"> + <div class="span12 offset0 content" + style="background-color: #84D5F4; color: #fff; height: 700px"> + <div class="text">Follow blog writers and view all their + articles plus the writers they follow.</div> + <img src="/img/features/profile-phone.jpg" + alt="Follow blog writers and view who they follow." /> + </div> + </div> + + </div> + + </div> + + <div class="row-fluid"> + <div class="span12 offset0 content" + style="background-color: #f1eee0; color: #666"> + <div class="row-fluid"> + <div class="span4"> + <div class="text">Watch a quick 30 seconds intro video + about the writer's purpose.</div> + </div> + <div class="span8"> + <img src="/img/features/video1.jpg" alt="Watch quick videos" /> + </div> + </div> + + </div> + </div> + + </div> + + + <div class="span4 offset0"> + + <div class="row-fluid"> + <div class="span12 offset0 content" + style="background-color: #FB840B; color: #fff; height: 700px"> + <div class="text">Beautiful. Casual. Simple. Clean. Fun.</div> + <img src="/img/features/reader-ipad.jpg" + alt="Simple. Casual. Simple. Clean. Fun." /> + </div> + </div> + + <div class="row-fluid"> + <div class="span12 offset0 content" + style="background-color: #00c7e1; color: #fff; height: 700px"> + <div class="text">Explore a category and preview 8 chosen + writers</div> + <img src="/img/features/writers-8.jpg" + alt="Explore writers by category." /> + </div> + </div> + + </div> + + </div> + + <div data-lift="MyBlog.entry" class="row-fluid" + style="margin: 100px 0"> + <h1 style="margin: 50px 0">Latest Blog Post</h1> + <div id="reader-nav-wrapper" class="span2 offset0"> + <div + class="reader-nav-blog reader-nav reader-span-spacing nolink-decoration"> + <ul id="reader-writers" class="nav text-center"> + <li id="writer"><a href=""> <img id="writer-image" src="" /> + </a> <a id="writer-name" href=""></a></li> + </ul> + + </div> + </div> + + <div id="boxed-articles-wrapper" class="span8 offset0"> + <div class="boxed-articles boxed-articles-span"> + <div class="article keynav-article"> + <div class="article-inner"> + <div class="article-key"></div> + <div class="row-fluid header text-center"> + <div class="span12"> + <a class="article-user-link" href=""> <img + id="article-user-image" src="" /> + </a> + <div class="writer-name nolink-decoration"> + <a id="article-user-name" class="article-user-link" href=""></a> + </div> + </div> + </div> + <div class="title"> + <a href="" target="_blank"></a> + </div> + <div class="row-fluid sub-header"> + <div class="span4 left-sub-header"> + <div class="left-sub-header-inner"> + <img src="" class="article-sharedby-img" /> <span>Shared + by <a class="article-sharedby"></a> + </span> + </div> + </div> + <div class="span8 right-sub-header"> + <time class="timeago" datetime=""></time> + <span class="article-share"></span> <span class="article-save"></span> + </div> + </div> + <span id="article-content"></span> + </div> + </div> + </div> + </div> + </div> + + </div> + + <div data-lift="ignore"> + <div id="writerswelove"></div> + <div class="container"> + <div class="articles"> + <div class="article text-center"> + <h2>Writers we Love</h2> + <p> + In Read Means, writers are celebrities because we believe writers + create content, not content creates writers. Check out our + featured writers that you can follow with <span class="readBlue">Read</span><span + class="readOrange"> means</span> + </p> + </div> + </div> + </div> + <span data-lift="embed?what=/templates-hidden/parts/writers-gallery"></span> + </div> + + + + <span data-lift="embed?what=/templates-hidden/parts/footer"></span> </div> diff --git a/src/main/webapp/reader.html b/src/main/webapp/reader.html @@ -1,100 +1,105 @@ <div data-lift="surround?with=base-wrap;at=content"> - <div class="container"> - <div data-lift="ReaderSnip.comingSoon"></div> - <div data-lift="ReaderSnip.articles" class="row-fluid"> - - <div id="reader-nav-wrapper" class="span2 offset0"> - <div id="reader-nav" class="reader-nav reader-span-spacing nolink-decoration"> - <ul id="reader-writers" class="nav text-center"> - <li id="writer"> - <a href=""> - <img id="writer-image" src="" /> - </a> - <a id="writer-name" href=""></a> - </li> - </ul> - - <div id="reader-categories"> - - <div class="scrollbar" style="float:left; display:none;"><div class="track"><div class="thumb"> - <div class="end"></div></div></div></div> - <div class="viewport" style="height:200px"> - <div class="overview" style="width:100%"> - <ul class="nav"> - - <li><a href="#">Sports</a></li> - <li><a href="#">Fashion</a></li> - <li><a href="#">Programming</a></li> - <li><a href="#">Technology</a></li> - <li><a href="#">Cooking</a></li> - <li><a href="#">Traveling</a></li> - <li><a href="#">Education</a></li> - - </ul> - </div> - </div> - - - </div> - - </div> - </div> - - <div id="boxed-articles-wrapper" class="span8 offset0"> - <div class="boxed-articles boxed-articles-span"> - <div class="article keynav-article"> - <div class="article-inner"> - <div class="article-key"></div> - <div class="row-fluid header text-center"> - <div class="span12"> - <a class="article-user-link" href=""> - <img id="article-user-image" src=""/> - </a> - <div class="writer-name nolink-decoration"> - <a id="article-user-name" class="article-user-link" href=""></a> - </div> - </div> - </div> - <div class="title"> - <a href="" target="_blank"></a> - </div> - <div class="row-fluid sub-header"> - <div class="span12"> - <time class="timeago" datetime=""></time> - <span class="article-share"></span> - <span class="article-save"></span> - </div> - </div> - <span id="article-content"></span> - </div> - </div> - </div> - </div> - - <div data-lift="ignore" class="span2 offset0"> - <div id="reader-ad-nav" class="reader-span-spacing text-center"> - <h5>Functional Programming</h5> - <ul class="nav nolink-decoration"> - <li> - <img src="https://secure.gravatar.com/avatar/7d6356b8b56a9a71583787904a970daa?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> - <a href="/julio">Julio Enrique Cabrera</a> - </li> - <li> - <img src="https://secure.gravatar.com/avatar/51e9266cad7460b23daac1179a72da2b?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> - <a href="/">Nathan Hamblen</a> - </li> - <li> - <img src="https://secure.gravatar.com/avatar/375ca615cb17ebcb05c417f3433fea4a?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> - <a href="/">Tim Nelson</a> - </li> - </ul> - </div> - </div> - - - </div> - </div> + <div class="container"> + <div data-lift="ReaderSnip.comingSoon"></div> + <div data-lift="ReaderSnip.articles" class="row-fluid"> + + <div id="reader-nav-wrapper" class="span2 offset0"> + <div id="reader-nav" + class="reader-nav reader-span-spacing nolink-decoration"> + <ul id="reader-writers" class="nav text-center"> + <li id="writer"><a href=""> <img id="writer-image" src="" /> + </a> <a id="writer-name" href=""></a></li> + </ul> + + <div id="reader-categories"> + + <div class="scrollbar" style="float: left; display: none;"> + <div class="track"> + <div class="thumb"> + <div class="end"></div> + </div> + </div> + </div> + <div class="viewport" style="height: 200px"> + <div class="overview" style="width: 100%"> + <ul class="nav"> + + <li><a href="#">Sports</a></li> + <li><a href="#">Fashion</a></li> + <li><a href="#">Programming</a></li> + <li><a href="#">Technology</a></li> + <li><a href="#">Cooking</a></li> + <li><a href="#">Traveling</a></li> + <li><a href="#">Education</a></li> + + </ul> + </div> + </div> + + + </div> + + </div> + </div> + + <div id="boxed-articles-wrapper" class="span8 offset0"> + <div class="boxed-articles boxed-articles-span"> + <div class="article keynav-article"> + <div class="article-inner"> + <div class="article-key"></div> + <div class="row-fluid header text-center"> + <div class="span12"> + <a class="article-user-link" href=""> <img + id="article-user-image" src="" /> + </a> + <div class="writer-name nolink-decoration"> + <a id="article-user-name" class="article-user-link" href=""></a> + </div> + </div> + </div> + <div class="title"> + <a href="" target="_blank"></a> + </div> + <div class="row-fluid sub-header"> + <div class="span4 left-sub-header"> + <div class="left-sub-header-inner"> + <img src="" class="article-sharedby-img" /> <span>Shared + by <a class="article-sharedby"></a> + </span> + </div> + </div> + <div class="span8 right-sub-header"> + <time class="timeago" datetime=""></time> + <span class="article-share"></span> <span class="article-save"></span> + </div> + </div> + <span id="article-content"></span> + </div> + </div> + </div> + </div> + + <div data-lift="ignore" class="span2 offset0"> + <div id="reader-ad-nav" class="reader-span-spacing text-center"> + <h5>Functional Programming</h5> + <ul class="nav nolink-decoration"> + <li><img + src="https://secure.gravatar.com/avatar/7d6356b8b56a9a71583787904a970daa?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> + <a href="/julio">Julio Enrique Cabrera</a></li> + <li><img + src="https://secure.gravatar.com/avatar/51e9266cad7460b23daac1179a72da2b?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> + <a href="/">Nathan Hamblen</a></li> + <li><img + src="https://secure.gravatar.com/avatar/375ca615cb17ebcb05c417f3433fea4a?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> + <a href="/">Tim Nelson</a></li> + </ul> + </div> + </div> + + + </div> + </div> diff --git a/src/main/webapp/saved.html b/src/main/webapp/saved.html @@ -1,77 +1,77 @@ <div data-lift="surround?with=base-wrap;at=content"> - <div class="container"> - <div data-lift="ReaderSnip.comingSoon"></div> - <div data-lift="ReaderSnip.savedArticles" class="row-fluid"> + <div class="container"> + <div data-lift="ReaderSnip.comingSoon"></div> + <div data-lift="ReaderSnip.savedArticles" class="row-fluid"> - <div id="reader-nav-wrapper" class="span2 offset0"> - <div id="reader-nav" class="reader-nav reader-span-spacing nolink-decoration"> - <ul id="reader-writers" class="nav text-center"> - <li id="writer"> - <a href=""> - <img id="writer-image" src="" /> - </a> - <a id="writer-name" href=""></a> - </li> - </ul> + <div id="reader-nav-wrapper" class="span2 offset0"> + <div id="reader-nav" + class="reader-nav reader-span-spacing nolink-decoration"> + <ul id="reader-writers" class="nav text-center"> + <li id="writer"><a href=""> <img id="writer-image" src="" /> + </a> <a id="writer-name" href=""></a></li> + </ul> - </div> - </div> + </div> + </div> - <div id="boxed-articles-wrapper" class="span8 offset0"> - <div class="boxed-articles boxed-articles-span"> - <div class="article keynav-article"> - <div class="article-inner"> - <div class="article-key"></div> - <div class="row-fluid header text-center"> - <div class="span12"> - <a class="article-user-link" href=""> - <img id="article-user-image" src=""/> - </a> - <div class="writer-name nolink-decoration"> - <a id="article-user-name" class="article-user-link" href=""></a> - </div> - </div> - </div> - <div class="title"> - <a href="" target="_blank"></a> - </div> - <div class="row-fluid sub-header"> - <div class="span12"> - <time class="timeago" datetime=""></time> - <span class="article-share"></span> - <span class="article-save"></span> - </div> - </div> - <span id="article-content"></span> - </div> - </div> - </div> - </div> + <div id="boxed-articles-wrapper" class="span8 offset0"> + <div class="boxed-articles boxed-articles-span"> + <div class="article keynav-article"> + <div class="article-inner"> + <div class="article-key"></div> + <div class="row-fluid header text-center"> + <div class="span12"> + <a class="article-user-link" href=""> <img + id="article-user-image" src="" /> + </a> + <div class="writer-name nolink-decoration"> + <a id="article-user-name" class="article-user-link" href=""></a> + </div> + </div> + </div> + <div class="title"> + <a href="" target="_blank"></a> + </div> + <div class="row-fluid sub-header"> + <div class="span4 left-sub-header"> + <div class="left-sub-header-inner"> + <img src="" class="article-sharedby-img" /> <span>Shared + by <a class="article-sharedby"></a> + </span> + </div> + </div> + <div class="span8 right-sub-header"> + <time class="timeago" datetime=""></time> + <span class="article-share"></span> <span class="article-save"></span> + </div> + </div> + <span id="article-content"></span> + </div> + </div> + </div> + </div> - <div data-lift="ignore" class="span2 offset0"> - <div id="reader-ad-nav" class="reader-span-spacing text-center"> - <h5>Functional Programming</h5> - <ul class="nav nolink-decoration"> - <li> - <img src="https://secure.gravatar.com/avatar/7d6356b8b56a9a71583787904a970daa?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> - <a href="/julio">Julio Enrique Cabrera</a> - </li> - <li> - <img src="https://secure.gravatar.com/avatar/51e9266cad7460b23daac1179a72da2b?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> - <a href="/">Nathan Hamblen</a> - </li> - <li> - <img src="https://secure.gravatar.com/avatar/375ca615cb17ebcb05c417f3433fea4a?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> - <a href="/">Tim Nelson</a> - </li> - </ul> - </div> - </div> + <div data-lift="ignore" class="span2 offset0"> + <div id="reader-ad-nav" class="reader-span-spacing text-center"> + <h5>Functional Programming</h5> + <ul class="nav nolink-decoration"> + <li><img + src="https://secure.gravatar.com/avatar/7d6356b8b56a9a71583787904a970daa?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> + <a href="/julio">Julio Enrique Cabrera</a></li> + <li><img + src="https://secure.gravatar.com/avatar/51e9266cad7460b23daac1179a72da2b?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> + <a href="/">Nathan Hamblen</a></li> + <li><img + src="https://secure.gravatar.com/avatar/375ca615cb17ebcb05c417f3433fea4a?s=80&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" /> + <a href="/">Tim Nelson</a></li> + </ul> + </div> + </div> - </div> - </div> + </div> + </div> diff --git a/src/main/webapp/templates-hidden/parts/blog-profile.html b/src/main/webapp/templates-hidden/parts/blog-profile.html @@ -110,7 +110,13 @@ <a href="" target="_blank"></a> </div> <div class="row-fluid sub-header"> - <div class="span12"> + <div class="span4 left-sub-header"> + <div class="left-sub-header-inner"> + <img src="" class="article-sharedby-img" /> + <span>Shared by <a class="article-sharedby"></a></span> + </div> + </div> + <div class="span8 right-sub-header"> <time class="timeago" datetime=""></time> <span class="article-share"></span> <span class="article-save"></span> diff --git a/src/main/webapp/templates-hidden/parts/user-profile.html b/src/main/webapp/templates-hidden/parts/user-profile.html @@ -96,7 +96,13 @@ <a href="" target="_blank"></a> </div> <div class="row-fluid sub-header"> - <div class="span12"> + <div class="span4 left-sub-header"> + <div class="left-sub-header-inner"> + <img src="" class="article-sharedby-img" /> + <span>Shared by <a class="article-sharedby"></a></span> + </div> + </div> + <div class="span8 right-sub-header"> <time class="timeago" datetime=""></time> <span class="article-share"></span> <span class="article-save"></span>