Customizing the Home Screen to show Tiles for Topics


(Patrick Burrows) #1

I have a special purpose forum I am making on top of Discourse where I want the latest posts for one of the categories (in this case “Book Reviews”) to display on the homescreen in the form of tiles. (all the other functionality of Discourse is the same)

Easy to do. In Admin, under Customize, Header, I added JavaScript that runs based on jQuery’s document ready event, and creates the tiles where I want them, doing a get on “/category/book-reviews/l/latest.json”. Everything works good.

However, when the user clicks on one of the tiles, and then uses the back button to go back to the home screen, the document.ready event never fires, so the tiles don’t get recreated. Instead, Ember is loading and rendering the views without reloading the page.

So, my question is: is there a quick / easy way to plugin to some equivalent of an Ember loading event that I can use to trigger my JavaScript functions?

I’ve used a lot of similar javascript frameworks before (knockout, angular), but not Ember specifically.

The whole thing has taken me about 20 minutes to do, except this last step which has got me stopped. I don’t want to take a bunch of time and learn Ember if I don’t have to.

Thanks for the help in advance. (No doubt I’ll figure this out as soon as I hit send…)


Material Design Stock Theme
Tiles for topics
Developer for Hire to help setup topic tiles?
(Patrick Burrows) #2

Ok, as I predicted, I got this working almost as soon as I posted this. Using @sam code from this post I was able to call my “createTiles” function whenever the homescreen is loaded by Ember.

I am detecting the homescreen with this:

if(window.location.pathname == "/")

Perhaps there is a better way to do it, but this is good for my purposes.

For posterity, below is the full working code and stylesheet. No doubt I’ll make more changes before it is published, but this creates the basic effect:

Create a new style in /admin/customize/css_html. Add this code to the “Header” tab:

<script type="text/javascript">
    var createdTiles = false;


    Discourse.Route.reopen({
        activate: function() {
            this._super();
            Em.run.next(function(){
                if(window.location.pathname == "/"){
                        createdTiles = false;
                        createTiles();
                }
              
            });
        } 
    });


    function createTiles(){
        
        if(createdTiles === true) return;
        createdTiles = true;
        
        var $listControls = $(".list-controls");
        
        var html = "<div id='TilesContainer' class='container'><h1>Latest Book Reviews</h1><div id='TilesOuterContainer'></div></div>";
        $listControls.before(html);
       
        $.get("/category/book-reviews/l/latest.json", handleLatestBookReviewsReceieved)
    }
    
    function handleLatestBookReviewsReceieved(resp, status, ele){
        var width = $("#topic-list").width();
        var tiles = "<div class='tiles-parent' style='width:" + width + "px;'>";
        for (var i = 0; i < resp.topic_list.topics.length; i++) {
            var topic = resp.topic_list.topics[i];
            
            if(topic.image_url !== null){
                tiles += "<div class='tile' style='background-image: url(" + topic.image_url + ")'>";
            } else {
                tiles += "<div class='tile'>";
            }
            
            tiles += "<div class='tile-hover'>";
            
            tiles += "<div class='tile-title'><a href='/t/" + topic.slug + "/" + topic.id + "'>" + topic.fancy_title + "</a></div>";
            
            tiles += "</div>"; //tile-hover
            
            tiles += "</div>"; //tile
        }
        tiles += "</div>";
        
        $("#TilesOuterContainer").html(tiles);
        
        $(".tile").hover(tileHoverOn, tileHoverOff)
    }
    
    function tileHoverOn(evt){
        $(this).find(".tile-hover").fadeIn();
    }
    
    function tileHoverOff(evt){
        $(this).find(".tile-hover").fadeOut();
    }
    
    
    
</script>

In the Stylesheet, add this code:

#TilesContainer{
    margin-bottom:4em;
}
#TilesContainer h1{
    margin-bottom:8px;
}
.tiles-parent{
    float:none;
    clear:both;
    max-height:900px;
    width:600px;
}
.tile{
    background-color: teal;
    background-repeat:no-repeat;
    float:left;
    height: 300px;
    width: 250px;
    background-size: 200% 200%;
    background-position:center;
    position:relative;
}
.tile-hover{
    position:absolute;
    width:100%;
    height: 300px;
    width: 250px;
    background: rgba(240, 101, 87, 0.8);
    display:none;
}

.tile-title{
    color: #ffffff;
    font-size:41px;
    height:100%;
    line-height:41px;
    padding-top: 20%;
    text-align: center;
    vertical-align:middle;
    width: 100%;
}

.tile-title a{
    color: inherit;
    text-decoration:none;
}

This doesn’t use fancy EmberJS views or handlebar templates, or anything like that. Just quick and dirty POJq (Plain Old JQuery). It’s nice. though, in that you can do everything from the admin screen and not have to mess with files.


Material Design for Discourse
Help with custom javascript for manual banner ads
Lists of topics not in table
showOpLikes - How to enable?
How do you force a script to refire on every page load in Discourse?
(Erlend Sogge Heggen) #3

Been pondering similar ideas, like having a Trello-like interface for a Discourse “Roadmap” category.

If this is a public forum I’d love to get a link. If not, just a screenshot or two would be greatly appreciated :slight_smile: And thanks for thinking about this out loud.


(Patrick Burrows) #4

It isn’t public yet, but here is a screenshot with dummy data. There is a mouseover effect on the tiles you cannot see because, well, screenshots don’t do that.

Doing a trello-like interface would be more complex, of course. It is more than just simple tiles – each column has its own meaning. But I think it is certainly buildable on top of Discourse. State tracking would probably best be done with categories (a category for each state, and have each column just read the latest items out of that category.)

The “hard” part would be ordering the tiles in each column. Date Last Modified likely wouldn’t be sufficient.


(smartwatchme) #5

We have incorporated tiles on our Discourse forum with modifications to the CSS and header based on what @CleverPatrick has started here.

We are also using @sam’s Personal minimalist topic list design


Personalization Plugin
#6

@smartwatchme Hello sir, could you be kind and copy/paste your full code that you’ve used i would like to have it same as your… but i’ll modify it abit more in css. God bless! :smile:


(Panteen Pro-V) #7

I did exactly the same like your instruction but nothing show up… I really have no idea why.


#8

I noticed that @smartwatchme was using Owl Carousel for their design. The benefit of Owl Carousel, is that it can easily take a JSON entry to help populate your tiles. I’m hesitant to post any code that is not 100% mine, but many people seem to be struggling with this and considering that a good portion of it was created using code that has already been posted here, I think it is the only way to improve upon this functionality.

Building off of @CleverPatrick patrick’s example, and @smartwatchme refinement of the Javascript, I was able to use the following Javascript to reach my result.

var createdTiles = false;
    Discourse.Route.reopen({
        activate: function() {
            this._super();
            Em.run.next(function(){
                if(window.location.pathname == "/"){
                        createdTiles = false;
                        createTiles();
                }
            });
        } 
    });

    function createTiles(){
        if(createdTiles === true) return;
        createdTiles = true;
        
        var $listControls = $(".list-controls");
        var html = "<div id='TilesContainer' class='container'><div class='main-slider'><div id='variation' class='owl-carousel'></div></div></div>";
        $listControls.before(html);
        
        var owl = $("#variation");
  		owl.owlCarousel({
			 jsonPath : 'c/games/l/latest.json', //path to the topics you want to show
			 items : 4, //4 items above 1000px browser width
			 itemsDesktop : [1000,4], //4 items between 1000px and 901px
			 itemsDesktopSmall : [900,3], // 3 betweem 900px and 601px
			 itemsTablet: [600,2], //2 items between 600 and 0
			 itemsMobile : false, // itemsMobile disabled - inherit from itemsTablet option
   			 navigation : true,
			 pagination: false,
			 autoPlay : false,
    		         stopOnHover : true,
			 jsonSuccess : customDataSuccess
		  });
		 function customDataSuccess(resp, status, ele){
			 
			var tiles = "";
			if (resp.topic_list.topics.length >8)
				var arraylength = 8;
			else
				var arraylength = resp.topic_list.topics.length;	
			for (var i = 0; i < arraylength; i++) {
				var topic = resp.topic_list.topics[i];
				
			
				
				tiles += "<div class='item'>";
				 if(topic.image_url !== null){
                tiles += "<div class='icw-img' style='background-image: url(" + topic.image_url + ")'></div>";
				} else {
					tiles += "<div class='icw-img' style='background-image: url(//*url for your placeholder image*/)'></div>";
				}
					tiles += "<a class='tile-hover' href='/t/" + topic.slug + "/" + topic.id + "/last'>";
						tiles += "<h2 class='tile-title'>" + topic.fancy_title + "</h2>";
						
						var d = new Date(topic.bumped_at);	
						var relative = moment(d, "ddd MMMM DD YYYY hh:mm:ss").fromNow();
						
						tiles += "<div class='tile-info'>Updated " + relative + "<br>by <strong>" + topic.last_poster_username + "</strong><br><div class='comment-btn'><span class='fa-stack fa-2x'><i class='fa fa-comment fa-stack-2x'></i><strong class='fa-stack-1x comment-count fa-inverse'>" + topic.posts_count + "</strong></span></div></div>"; //tile
					    
					tiles += "</a>"; //tile-hover
				tiles += "</div>"; //tile
			}
			
			$("#variation").html(tiles);
		}
    }

Category image gallery possible?
Material Design for Discourse
(Sumbuddy That Yuuu Yuustuno) #9

Everytime i try to use Your javascript code coupled with the css i made; the carousel will just not show up.
I can see from the chrome inspector that html for Tile Container, main slider etc is added. The console shows the following error:

Uncaught TypeError: undefined is not a function(index):372
createTiles.

The error is shown next to this line of the code:
owl.owlCarousel({

I think im missing something. Anybody who can help me out a bit here?


#10

Did you reference the owl carousel JavaScript itself somewhere? You also need to include that. You could either host it your self or use a hosting site like:

<script src="https://cdnjs.cloudflare.com/ajax/libs/owl-carousel/1.3.2/owl.carousel.min.js"></script>

#11

Thanks everyone for the great script samples. My question is, is there a way to make topic.image_url ignore emojis when choosing a background image for the tile?


(Régis Hanol) #12

Just pushed a fix that makes sure we don’t use emojis as topic images :ram:

https://github.com/discourse/discourse/commit/82d743a052df85b1dfef2410759b1b26c9d51b2a


#13

Super fast, thank you! Now the only thing is, how can I regenerate the old topic images? do I do a
rake posts:rebake ?


Add a slider show on header
(Régis Hanol) #14

A rebake would do the trick.

SSH into your server and then

cd /var/discourse
./launcher enter app
rake posts:rebake

Get list of topics client side
Show excerpt for all topics via a theme
Show excerpt for all topics via a theme
(DjCyry) #15

I cant get it work : http://www.tupics.net/image/hB3
I have modified ther line

 $.get("/category/stiri-noutati/l/latest.json", handleLatestBookReviewsReceieved)

And also i :

cd /var/discourse
./launcher enter app
rake posts:rebake

Can anyone help me ? thanks


#16

Have you tried using:

$.get("/c/stiri-noutati/l/latest.json", handleLatestBookReviewsReceieved)

so essentially just changing category to c instead?


(DjCyry) #17

Yes @rewphus but : http://www.tupics.net/image/hBX
And its showing all the topics of that category .
Also its showing 3 times that : http://www.tupics.net/image/hBl


#18

What I think is happening is that the createTIles function is being called multiple times without properly terminating, causing it to duplicate your label. It was hardly noticeable for me at first because I wasn’t using a label, but I noticed the space between the navigation links and the tiles grew larger and larger each time I revisited the page. When I looked in to it I found that the TilesContainer div was duplicated multiple times, but only one of them actually contained any content.

Someone much smarter than me could probably figure out how to easily adjust the above code so that doesn’t happen. I ended up creating a personal plugin that ran a bunch of ugly triggers to check if the function had already ran, and if so, not to run again. I have only played with this plugin in a dev environment, however, so I’m not really sure how stable it is, or if it’s even the problem you are experiencing. I can see if that might be the case if you want to provide a link to your site, or you could check yourself using the inspector and see if the TilesContainer div is showing multiple times.


(Marco) #19

Hi, I put the codes, but to me it is not working…
I get a blank page in response…


#20

It looks like your site might be private. Do you have your attempt hosted somewhere that I could look at?