Tumblr Themes & React and Redux: Part 1 - Setup and the Initial State

engineering:

image

As a platform that prides itself on being a home for artists and creatives alike, it only makes sense that we allow our users to fully customize their Tumblrs to fully express themselves. Here at Tumblr, the world is your oyster not only in terms of looks but also in how you create your theme. I wanted to demonstrate how you too can develop a theme using Redux and React. Since there are plenty of docs and tutorials on how to use those libraries themselves, I will briefly describe how I got the libraries to work with the Tumblr theme engine, and share some handy tips that made developing more efficient and more enjoyable.

If you follow the ever changing landscape of JavaScript, then you’ve at least heard of these two libraries. Prior to building the Post-It-Forward theme, I only knew of them by name but never got the chance to actually use them. Developers couldn’t get enough of how React made it easy to create and reuse components. Many also praise how elegantly React manages and renders views, especially when paired with Redux for state management. All of this sounded great. I wanted to turn this project into a learning experience. I thought, “why not?” and gave it a shot.

An Extremely Brief Introduction to Tumblr Themes

The way themes work on Tumblr is that we have a theme engine that provides special types of operators. These operators insert dynamic data, such as your Tumblr’s title or description, or are blocks that serve as conditionals for rendering a block of HTML, like the “Next Page” link.

My HTML started off a little something like this:

<!DOCTYPE html>
    <head>
    <title>{Title}</title>
        <style></style>
    </head>
    <body>
        <div id="post-it-forward-root"></div>
    </body>
</html>

As you can see, {Title} is a variable that will return the title of the Tumblr. The point of entry for this theme is the <div> element with the #post-it-forward-root ID. In your index.js file you’ll reference this DOM element in your ReactDom.render() method. If you want to learn more about the theme engine, head over to our Theme Docs

Creating the Initial State

To get things started, we need to create an initial state. How do we introduce this initial state if we have to rely on the theme engine to give us all our data? How do we get the data from HTML land to JS land? Well, here’s one way of doing it:

<script type="text/javascript">
    (function(root) {
        var ensureString = function(str) {
            return !str ? '' : str;
        };

        var basicVariables = {
            title: ensureString({JSTitle}),
            name: ensureString({JSName}),
                        description: ensureString({JSDescription}),
                        metaDescription: ensureString({JSMetaDescription}),
                        blogUrl: ensureString({JSBlogURL}),
                        rss: ensureString({JSRSS}),
            favicon: ensureString({JSFavicon}),
            customCss: ensureString({JSCustomCSS}),
            isPermalinkPage: !!ensureString(/*{block:PermalinkPage}*/true/*{/block:PermalinkPage}*/),
            isIndexPage: !!ensureString(/*{block:IndexPage}*/true/*{/block:IndexPage}*/),
            /*{block:PostTitle}*/
            postTitle: ensureString({JSPostTitle}),
            /*{/block:PostTitle}*/
            /*{block:PostSummary}*/
            postSummary: ensureString({JSPostSummary}),
            /*{/block:PostSummary}*/
            portraitUrl16: ensureString({JSPortraitURL-16}),
            portraitUrl24: ensureString({JSPortraitURL-24}),
            portraitUrl30: ensureString({JSPortraitURL-30}),
            portraitUrl40: ensureString({JSPortraitURL-40}),
            portraitUrl48: ensureString({JSPortraitURL-48}),
            portraitUrl64: ensureString({JSPortraitURL-64}),
            portraitUrl96: ensureString({JSPortraitURL-96}),
            portraitUrl128: ensureString({JSPortraitURL-128}),
            copyrightYears: ensureString({JSCopyrightYears}),
            isSearchPage: !!ensureString(/*{block:SearchPage}*/true/*{/block:SearchPage}*/),
            searchQuery: ensureString({JSSearchQuery}),
            safeSearchQuery: ensureString({JSURLSafeSearchQuery}),
            searchPlaceHolder: ensureString('{lang:Search Blog}'),
            noSearchResults: !!ensureString(/*{block:NoSearchResults}*/true/*{/block:NoSearchResults}*/),
        };

        root.tumblrData = {
            basicVariables: basicVariables,
            };
    })(this);
</script>

This creates a tumblrData attribute on the browser’s window object.

Sometimes the theme engine returns nothing for a particular variable if it’s not available. For example, if I made a post that does not have a title, the final root.tumblrData object will not have postTitle as a key. Sometimes the key will be available but the theme engine returned an empty value for it. For those cases, I created a helper method called ensureString() that turns those empty values into empty strings. Sometimes you might need a boolean value. In those cases, I’ll enter the conditional variables from the theme engine into the helper method to get the boolean value from it.

Once you’ve set up your initial state make sure that you place this script tag before the script tag that references the rest of your code that should be compiled and minified and uploaded through the asset uploader that the Tumblr text editor provides. This ensures that the tumblrData is accessible through the window object by the time the React app gets initiated.

tumblrData should look something like this:

const tumblrData = {
    basicVariables: {
        blogUrl: "https://mentalhealthquilt.tumblr.com/",
        copyrightYears: "2016–2017",
        customCss: "",
                description: "Mental Health Quilt",
        favicon: "https://68.media.tumblr.com/avatar_c402eedfb9d5_128.png",
        isIndexPage: true,
        isPermalinkPage: false,
        isSearchPage: false,
        metaDescription: "Mental Health Quilt",
        name: "mentalhealthquilt",
        noSearchResults: false,
        portraitUrl16: "https://68.media.tumblr.com/avatar_c402eedfb9d5_16.png",
        portraitUrl24: "https://68.media.tumblr.com/avatar_c402eedfb9d5_24.png",
        portraitUrl30: "https://68.media.tumblr.com/avatar_c402eedfb9d5_30.png",
        portraitUrl40: "https://68.media.tumblr.com/avatar_c402eedfb9d5_40.png",
        portraitUrl48: "https://68.media.tumblr.com/avatar_c402eedfb9d5_48.png",
        portraitUrl64: "https://68.media.tumblr.com/avatar_c402eedfb9d5_64.png",
        portraitUrl96: "https://68.media.tumblr.com/avatar_c402eedfb9d5_96.png",
        portraitUrl128: "https://68.media.tumblr.com/avatar_c402eedfb9d5_128.png",
        rss: "https://mentalhealthquilt.tumblr.com/rss",
        safeSearchQuery: "",
        searchPlaceHolder: "Search mentalhealthquilt",
        searchQuery: "",
        title: "Mental Health Quilt",
    },
}

Now we have the data that the theme engine gave us in a format that React and Redux can work with.

If you are new to these libraries, I highly recommend following the simple Todo App Tutorial that is on the Redux website. They do a wonderful job of explaining the process as you build the app.

Helpful Tips

Setting up a local server will make developing way faster than the current setup. If you’re using both the “webpack” and “webpack-dev-server” packages, in your package.json file under scripts you can place something like this in it:

In your package.json file

...
"scripts": {
    "local-server": "NODE_ENV=development webpack-dev-server --config path/to/webpack.config.js --port=3000 --inline --hot"
},
...

To run that script, in the terminal you will type this command:

> npm run local-server

In the Tumblr editor, be sure to replace your script tags referencing these external files like so:

<!DOCTYPE html>
        <head>
                <title>{Title}</title>
                <link rel="stylesheet" type="text/css" href="http://localhost:3000/path/to/prod/index.css">
        </head>
        <body>
                <div id="post-it-forward-root"></div>
                <script type="text/javascript">
                        // where the tumblrData gets created
                </script>
                <script src="http://localhost:3000/path/to/prod/index.js"></script>
        </body>
</html>

Once you run that script, it’ll enable live reload so that every time you save a .js_.css_.scss/etc. file, it’ll rebuild the assets and refresh your Tumblr blog for you. This is way faster than having to re-upload your assets every time you make a change, no matter how small. Just remember to return your script and style references to the uploaded assets when you’re done working. Localhost is only for development.

You could also add the Redux logger middleware to your project during development so that you can view how the state changes as you fire off different actions. For more information on how to set this up, the Redux Logger Github is a great resource.

Summary

Building a Tumblr theme using Redux and React is possible! Not only is there a workflow that makes development much faster, but it’s also a great way to flex your web development muscles. You can add more to the user experience of your Tumblr now that you have the world of JavaScript at your fingertips. Go forth and make some awesome themes!

Stay tuned for part 2 that will cover paginating.

- @0xmichelle

Eres un error que no paro de cometer

“El fracaso no es el final de todo. Si eres valiente será el comienzo de un todo.”

- Stup (via s-t-u-p-7-d)

p-ara4dox:

Todos te quieren solamente cuando estás de buen humor

Todos te quieren solamente cuando estás de buen humor

quinceava:

💜💜💜💜💜💜

goamantedeletras:

Vas a tener 16 solo por 365 días. y puedes morir a los 17. Cuando tu mamá te pregunte si quieres dormir en su cama, di que si. Un día ella va a estar en una cama de hospital y no habrá suficiente espacio para hacerlo. Deja de cancelar planes; sal y usa tus piernas mientras funcionan. No tienes nada garantizado. Deja de negar el afecto. No vas a poder amar a alguien como adolescente a los 35 años. Alguien, muchos alguien, te van a decir que te aman. No te quedes quieta por que te lo dijeron muy pronto. Si los amas, díselos. Se brutalmente honesta. Ve afuera y cambia el mundo. Pelea por paz, igualdad y un cambio. Cuando tengas 70 y solo puedas ver las noticias todo el día no querrás ver los mismos problemas cuando tu tuviste la oportunidad de pelear. Deja de utilizar el ‘’No necesito a nadie’’ ‘’No tengo sentimientos’’ como actitud. Es fácil hacer amigos en la secundaria que en un hogar para ancianos. Abraza los sentimientos y la intimidad. No te disculpes por preocuparte y no dejes que nadie te haga sentir culpable por preocuparte incluso si es por ellos. Solo eres un adolescente 2,555 días y luego cumples La vida nunca avanza mas lento. Los huesos se vuelven frágiles y se rompen, la gente muere, y el corazón se hace débil. Vive con cada átomo de tu cuerpo, Ahora.

El dragón rojo & el zorro blanco

p-ara4dox:

Existe una leyenda, conocida por pocos, sobre una batalla entre un gran dragón rojo y un pequeño zorro blanco.

Bueno, ya todos nos imaginamos el resultado de este confortamiento ¿No?

Pues déjame decirte que muchos se sorprendieron al escuchar el final de esta leyenda, ya que el gran, letal y solitario dragón rojo cayó a los pies de el inocente, pequeño e ingenuo zorro blanco.

¿Cómo? Fácil.

El dragón se enamoró.

-Paradox-

El dragón rojo & el zorro blanco

Existe una leyenda, conocida por pocos, sobre una batalla entre un gran dragón rojo y un pequeño zorro blanco.

Bueno, ya todos nos imaginamos el resultado de este confortamiento ¿No?

Pues déjame decirte que muchos se sorprendieron al escuchar el final de esta leyenda, ya que el gran, letal y solitario dragón rojo cayó a los pies de el inocente, pequeño e ingenuo zorro blanco.

¿Cómo? Fácil.

El dragón se enamoró.

-Paradox-

“Quien jode un corazón y abusa de una oportunidad, a la otra vida le tocará esperar.”

- Stup (via s-t-u-p-7-d)
SY