{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Using Nikola to blog with ipython notebooks.\n", "\n", "http://www.damian.oquanta.info/posts/ipython-plugin-for-nikola-updated.html\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "toc": "true" }, "source": [ "

Table of Contents

\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Installing Nikola" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Update January 2020:** I recommend installing Nikola from a conda `environment.yml` file. I keep one on [anaconda cloud](https://anaconda.org/mforbes/blog) so you can just go:\n", "\n", "```bash\n", "conda env create mforbes/blog\n", "such as the following:\n", "\n", "```yml\n", "# environment.yml\n", "name: blog\n", "channels:\n", " - defaults\n", " - conda-forge\n", " - mforbes\n", "dependencies:\n", " - jinja2 # Jinja2 Template engine for my styles.\n", " - nbstripout # Cleaning output from notebooks\n", " - typogrify # Required for the typogrify filter\n", "\n", " # These are needed by Nikola. We install them so Conda has control.\n", " - babel>=2.6.0\n", " - blinker>=1.3\n", " - docutils>=0.13\n", " - doit>=0.32.0\n", " - lxml>=3.3.5\n", " - mako>=1.0.0\n", " - markdown>=3.0.0\n", " - natsort>=3.5.2\n", " - piexif>=1.0.3\n", " - pillow>=2.4.0\n", " - pygments>=1.6\n", " - python-dateutil>=2.6.0\n", " - requests>=2.2.0\n", " - setuptools>=24.2.0\n", " - unidecode>=0.04.16\n", " - yapsy>=1.11.223\n", "\n", " # Additional dependencies not in conda - they will be installed by pip.\n", " #- PyRSS2Gen>=1.1\n", " \n", " # Needed of ipynb format\n", " - nbconvert\n", " - notebook>=4.0.0\n", "\n", " # Needed for nikola auto\n", " - watchdog>=0.8.3 # Conda version gives \"Failed to import fsevents. Fall back to kqueue\"\n", " - aiohttp\n", "\n", " # My packages.\n", " - mmf_setup\n", "\n", " - pip\n", " - pip:\n", " #- nikola>=8.1.1\n", " # Need dev version for this issue with templates\n", " # https://github.com/getnikola/nikola/issues/3457\n", " - git+https://github.com/getnikola/nikola.git@master\n", " - pipdeptree\n", " #- watchdog>=0.8.3\n", " - ghp-import2 # Needed for github_deploy\n", " \n", " #- pyrss2gen>=1.1\n", " #- python-hglib==2.6.1\n", "```\n", "\n", "There is no conda recipe yet for Nikola, so it needs to be pip installed.\n", "\n", "To uses some html features like SASS, I needed to install `npm` which I did at the system level.\n", "\n", "```bash\n", "conda env create -f environment.blog.yml\n", "conda activate blog\n", "npm install -g less # lessc compiler required for CSS in zen- themes\n", "sudo gem install sass # sass compiler required for SASS based CSS\n", "nikola plugin -i less\n", "nikola plugin -i sass\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Old Notes and Problems" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I had some trouble pip-installing nikola with pip so had to install a few of the dependencies first with conda." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Collecting nikola\n", " Using cached Nikola-7.7.6-py2.py3-none-any.whl\n", "Requirement already satisfied (use --upgrade to upgrade): webassets in /data/apps/anaconda/envs/work/lib/python2.7/site-packages\n", "Requirement already satisfied (use --upgrade to upgrade): natsort>=3.5.2 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): docutils>=0.12 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): doit<=0.29.0,>=0.28.0 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): unidecode>=0.04.16 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): python-dateutil>=2.4.0 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): requests>=2.2.0 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): Pygments>=1.6 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): lxml>=3.3.5 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): blinker>=1.3 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): husl>=4.0.2 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): logbook>=0.7.0 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): Pillow>=2.4.0 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): PyRSS2Gen>=1.1 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): mako>=1.0.0 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): Yapsy>=1.11.223 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): setuptools>=5.4.1 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages/setuptools-20.1.1-py2.7.egg (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): six in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from doit<=0.29.0,>=0.28.0->nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): macfsevents in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from doit<=0.29.0,>=0.28.0->nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): configparser in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from doit<=0.29.0,>=0.28.0->nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): MarkupSafe>=0.9.2 in /data/apps/anaconda/envs/work/lib/python2.7/site-packages (from mako>=1.0.0->nikola)\n", "Installing collected packages: nikola\n", "Successfully installed nikola-7.7.6\n" ] } ], "source": [ "# This worked with python 3 in an anaconda install.\n", "!pip install nikola webassets\n", "!conda install ws4py watchdog # Required for nikola auto\n", "!pip install typogrify # Required for the typogrify filter\n", "!npm install -g less # lessc compiler required for CSS in zen- themes\n", "!sudo gem install sass # sass compiler required for SASS based CSS\n", "!nikola plugin -i less\n", "!nikola plugin -i sass" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Fetching package metadata: ..........\n", "Solving package specifications: .\n", "# All requested packages already installed.\n", "# packages in environment at /data/apps/anaconda/1.3.1:\n", "#\n", "pillow 2.7.0 py27_0 \n", "Requirement already satisfied (use --upgrade to upgrade): nikola in /data/src/python/git/nikola\n", "Requirement already satisfied (use --upgrade to upgrade): livereload in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages\n", "Collecting webassets\n", " Downloading webassets-0.10.1.tar.gz (167kB)\n", "\u001b[K 100% |################################| 167kB 386kB/s \n", "\u001b[?25hRequirement already satisfied (use --upgrade to upgrade): doit>=0.23.0 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): Pygments>=1.6 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): Pillow>=2.4.0 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): python-dateutil==2.4.0 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): docutils>=0.12 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): mako>=1.0.0 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): unidecode>=0.04.16 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): lxml>=3.3.5 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): yapsy>=1.10.423 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): PyRSS2Gen>=1.1 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): logbook>=0.7.0 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): blinker>=1.3 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Collecting setuptools>=5.4.1 (from nikola)\n", " Using cached setuptools-12.1-py2.py3-none-any.whl\n", "Requirement already satisfied (use --upgrade to upgrade): natsort>=3.5.2 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): tornado in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from livereload)\n", "Requirement already satisfied (use --upgrade to upgrade): six in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from doit>=0.23.0->nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): macfsevents in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from doit>=0.23.0->nikola)\n", "Requirement already satisfied (use --upgrade to upgrade): MarkupSafe>=0.9.2 in /data/apps/anaconda/1.3.1/lib/python2.7/site-packages (from mako>=1.0.0->nikola)\n", "Installing collected packages: setuptools, webassets\n", " Found existing installation: distribute 0.6.45\n", " Uninstalling distribute-0.6.45:\n", " Successfully uninstalled distribute-0.6.45\n", "\n", " Running setup.py install for webassets\n", " Installing webassets script to /data/apps/anaconda/1.3.1/bin\n", "Successfully installed setuptools-0.6rc11 webassets-0.10.1\n", "Fetching package metadata: ..........\n", "# All requested packages already installed.\n", "# packages in environment at /data/apps/anaconda/1.3.1:\n", "#\n", "lxml 3.4.2 py27_0 \n" ] } ], "source": [ "# I needed this before with python 2\n", "!conda install pillow\n", "!pip install nikola livereload webassets\n", "!conda update lxml" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Compiler" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I had trouble installing ``macfsevents`` using the HPC compilers, so I had to disable them. When using the Xcode compilers, everything worked." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Lack of Root Permissions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you don't have root access, then running `npm` or `gem` might cause issues (i.e. on Sage Mathcloud.) For `npm`, the [suggestion here](http://stackoverflow.com/a/23889603/1088938) to:\n", "\n", "```bash\n", "npm config set prefix ~/.npm\n", "cat > ~/.bash_aliases <\n", "MathJax.Hub.Config({\n", " tex2jax: {\n", " inlineMath: [ ['$','$'], [\"\\\\\\(\",\"\\\\\\)\"] ],\n", " displayMath: [ ['$$','$$'], [\"\\\\\\[\",\"\\\\\\]\"] ],\n", " processEscapes: true\n", " },\n", " displayAlign: 'left', // Change this to 'center' to center equations.\n", " \"HTML-CSS\": {\n", " styles: {'.MathJax_Display': {\"margin\": 0}}\n", " }\n", "});\n", "\n", "\"\"\"\n", "```" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Comments" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I am trying the [Disqus](http://disqus.com/) comment system since this was recommended in the Nikola manual. I had to create a Disqus account, and then register a new site to get the ``shortname``. Some immediately apparent issues:\n", "\n", "* Disqus puts a lot of things in a global namespace. For example, the username (my usual handle was already taken) and when registering a new site, you need to guess a unique identifier ``.disqus.com``." ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Website" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nikola can also be used for a [static website](https://getnikola.com/creating-a-site-not-a-blog-with-nikola.html). Here is the list of packages and versions I used when doing this:\n", "\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# packages in environment at /data/apps/conda/envs/blog:\r\n", "#\r\n", "# Name Version Build Channel\r\n", "aiohttp 3.6.2 py36h1de35cc_0 \r\n", "appnope 0.1.0 py36hf537a9a_0 \r\n", "argh 0.26.2 py36_0 \r\n", "argon2-cffi 20.1.0 py36haf1e3a3_1 \r\n", "async-timeout 3.0.1 py36_0 \r\n", "async_generator 1.10 py36h28b3542_0 \r\n", "attrs 20.2.0 py_0 \r\n", "babel 2.8.0 py_0 \r\n", "backcall 0.2.0 py_0 \r\n", "bleach 3.2.1 py_0 \r\n", "blinker 1.4 py36_0 \r\n", "brotlipy 0.7.0 py36haf1e3a3_1000 \r\n", "ca-certificates 2020.7.22 0 \r\n", "certifi 2020.6.20 py36_0 \r\n", "cffi 1.14.3 py36hed5b41f_0 \r\n", "chardet 3.0.4 py36_1003 \r\n", "cloudpickle 1.6.0 py_0 \r\n", "cryptography 3.1.1 py36hddc9c9b_0 \r\n", "decorator 4.4.2 py_0 \r\n", "defusedxml 0.6.0 py_0 \r\n", "docutils 0.16 py36_1 \r\n", "doit 0.32.0 py36_0 \r\n", "entrypoints 0.3 py36_0 \r\n", "freetype 2.10.2 ha233b18_0 \r\n", "ghp-import2 1.0.1 pypi_0 pypi\r\n", "icu 58.2 h0a44026_3 \r\n", "idna 2.10 py_0 \r\n", "idna_ssl 1.1.0 py36_0 \r\n", "importlib-metadata 1.7.0 py36_0 \r\n", "importlib_metadata 1.7.0 0 \r\n", "ipykernel 5.3.4 py36h5ca1d4c_0 \r\n", "ipython 7.16.1 py36h5ca1d4c_0 \r\n", "ipython_genutils 0.2.0 py36_0 \r\n", "jedi 0.17.2 py36_0 \r\n", "jinja2 2.11.2 py_0 \r\n", "jpeg 9b he5867d9_2 \r\n", "jsonschema 3.2.0 py36_1 \r\n", "jupyter_client 6.1.7 py_0 \r\n", "jupyter_core 4.6.3 py36_0 \r\n", "jupyterlab_pygments 0.1.2 py_0 \r\n", "lcms2 2.11 h92f6f08_0 \r\n", "libcxx 10.0.0 1 \r\n", "libedit 3.1.20191231 h1de35cc_1 \r\n", "libffi 3.3 hb1e8313_2 \r\n", "libiconv 1.16 h1de35cc_0 \r\n", "libpng 1.6.37 ha441bb4_0 \r\n", "libsodium 1.0.18 h1de35cc_0 \r\n", "libtiff 4.1.0 hcb84e12_1 \r\n", "libxml2 2.9.10 h3b9e6c8_1 \r\n", "libxslt 1.1.34 h83b36ba_0 \r\n", "lxml 4.5.2 py36h63b7cb6_0 \r\n", "lz4-c 1.9.2 hb1e8313_1 \r\n", "macfsevents 0.8.1 py36h1de35cc_0 \r\n", "mako 1.1.3 py_0 \r\n", "markdown 3.3 py36_0 \r\n", "markupsafe 1.1.1 py36h1de35cc_0 \r\n", "mistune 0.8.4 py36h1de35cc_0 \r\n", "mmf_setup 0.3.0 py_0 mforbes\r\n", "multidict 4.7.6 py36haf1e3a3_1 \r\n", "natsort 7.0.1 py_0 \r\n", "nbclient 0.5.0 py_0 \r\n", "nbconvert 6.0.7 py36_0 \r\n", "nbformat 5.0.7 py_0 \r\n", "nbstripout 0.3.9 pyh9f0ad1d_0 conda-forge\r\n", "ncurses 6.2 h0a44026_1 \r\n", "nest-asyncio 1.4.1 py_0 \r\n", "nikola 8.1.1 pypi_0 pypi\r\n", "notebook 6.1.4 py36_0 \r\n", "olefile 0.46 py36_0 \r\n", "openssl 1.1.1h haf1e3a3_0 \r\n", "packaging 20.4 py_0 \r\n", "pandoc 2.10.1 0 \r\n", "pandocfilters 1.4.2 py36_1 \r\n", "parso 0.7.0 py_0 \r\n", "pathtools 0.1.2 py_1 \r\n", "pexpect 4.8.0 py36_0 \r\n", "pickleshare 0.7.5 py36_0 \r\n", "piexif 1.1.3 py_2 conda-forge\r\n", "pillow 7.2.0 py36ha54b6ba_0 \r\n", "pip 20.2.3 py36_0 \r\n", "pipdeptree 1.0.0 pypi_0 pypi\r\n", "prometheus_client 0.8.0 py_0 \r\n", "prompt-toolkit 3.0.7 py_0 \r\n", "ptyprocess 0.6.0 py36_0 \r\n", "pycparser 2.20 py_2 \r\n", "pygments 2.7.1 py_0 \r\n", "pyopenssl 19.1.0 py_1 \r\n", "pyparsing 2.4.7 py_0 \r\n", "pyrsistent 0.17.3 py36haf1e3a3_0 \r\n", "pyrss2gen 1.1 pypi_0 pypi\r\n", "pysocks 1.7.1 py36_0 \r\n", "python 3.6.12 h26836e1_2 \r\n", "python-dateutil 2.8.1 py_0 \r\n", "python-hglib 2.6.1 py_0 mforbes\r\n", "pytz 2020.1 py_0 \r\n", "pyyaml 5.3.1 py36haf1e3a3_1 \r\n", "pyzmq 19.0.2 py36hb1e8313_1 \r\n", "readline 8.0 h1de35cc_0 \r\n", "requests 2.24.0 py_0 \r\n", "send2trash 1.5.0 py36_0 \r\n", "setuptools 50.3.0 py36h0dc7051_1 \r\n", "six 1.15.0 py_0 \r\n", "smartypants 2.0.0 pyh9f0ad1d_2 conda-forge\r\n", "sqlite 3.33.0 hffcf06c_0 \r\n", "terminado 0.8.3 py36_0 \r\n", "testpath 0.4.4 py_0 \r\n", "tk 8.6.10 hb0a8c7a_0 \r\n", "tornado 6.0.4 py36h1de35cc_1 \r\n", "traitlets 4.3.3 py36_0 \r\n", "typing_extensions 3.7.4.3 py_0 \r\n", "typogrify 2.0.7 py36_0 conda-forge\r\n", "unidecode 1.1.1 py_0 \r\n", "urllib3 1.25.10 py_0 \r\n", "watchdog 0.10.3 py36haf1e3a3_0 \r\n", "wcwidth 0.2.5 py_0 \r\n", "webencodings 0.5.1 py36_1 \r\n", "wheel 0.35.1 py_0 \r\n", "xz 5.2.5 h1de35cc_0 \r\n", "yaml 0.2.5 haf1e3a3_0 \r\n", "yapsy 1.12.2 py_0 conda-forge\r\n", "yarl 1.6.0 py36haf1e3a3_0 \r\n", "zeromq 4.3.2 hb1e8313_3 \r\n", "zipp 3.3.0 py_0 \r\n", "zlib 1.2.11 h1de35cc_3 \r\n", "zstd 1.4.5 h41d2c2f_0 \r\n" ] } ], "source": [ "!conda list -n blog" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```bash\n", "$ nikola init forbes-group\n", "Creating Nikola Site\n", "====================\n", "\n", "This is Nikola v7.8.3. We will now ask you a few easy questions about your new site.\n", "If you do not want to answer and want to go with the defaults instead, simply restart with the `-q` parameter.\n", "--- Questions about the site ---\n", "Site title [My Nikola Site]: Forbes Group Website\n", "Site author [Nikola Tesla]: Michael McNeil Forbes\n", "Site author's e-mail [n.tesla@example.com]: m.forbes@wsu.edu\n", "Site description [This is a demo site for Nikola.]: Forbes Group Research Site\n", "Site URL [https://example.com/]: http://swan.physics.wsu.edu/forbes/\n", "Enable pretty URLs (/page/ instead of /page.html) that don't need web server configuration? [Y/n] \n", "--- Questions about languages and locales ---\n", "We will now ask you to provide the list of languages you want to use.\n", "Please list all the desired languages, comma-separated, using ISO 639-1 codes. The first language will be used as the default.\n", "Type '?' (a question mark, sans quotes) to list available languages.\n", "Language(s) to use [en]: \n", "\n", "Please choose the correct time zone for your blog. Nikola uses the tz database.\n", "You can find your time zone here:\n", "https://en.wikipedia.org/wiki/List_of_tz_database_time_zones\n", "\n", "Time zone [America/Vancouver]: \n", " Current time in America/Vancouver: 00:53:13\n", "Use this time zone? [Y/n] \n", "--- Questions about comments ---\n", "You can configure comments now. Type '?' (a question mark, sans quotes) to list available comment systems. If you do not want any comments, just leave the field blank.\n", "Comment system: disqus\n", "You need to provide the site identifier for your comment system. Consult the Nikola manual for details on what the value should be. (you can leave it empty and come back later)\n", "Comment system site identifier: forbes-group\n", "\n", "That's it, Nikola is now configured. Make sure to edit conf.py to your liking.\n", "If you are looking for themes and addons, check out https://themes.getnikola.com/ and https://plugins.getnikola.com/.\n", "Have fun!\n", "[2017-01-21T08:53:36Z] INFO: init: Created empty site at forbes-group.\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now version control the generated files:\n", "\n", "```bash\n", "cd forbes-group\n", "hg init\n", "hg add\n", "hg com -m \"Initial Commit\"\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now switch the theme to `zen-ipython` which requires installing some themes:\n", "\n", "```bash\n", "$ nikola install_theme zen-ipython\n", "[2017-01-21T09:01:18Z] WARNING: Nikola: Cannot load theme \"zen-ipython\", using 'bootstrap3' instead.\n", "[2017-01-21T09:01:18Z] INFO: theme: Downloading 'https://themes.getnikola.com/v7/zen-ipython.zip'\n", "[2017-01-21T09:01:19Z] INFO: theme: Extracting 'zen-ipython' into themes/\n", "[2017-01-21T09:01:19Z] NOTICE: theme: This theme has a sample config file. Integrate it with yours in order to make this theme work!\n", "Contents of the conf.py.sample file:\n", "\n", " NAVIGATION_LINKS = {\n", " DEFAULT_LANG: (\n", " ('/index.html', 'Home', 'icon-home'),\n", " ('/archive.html', 'Archives', 'icon-folder-open-alt'),\n", " ('/categories/index.html', 'Tags', 'icon-tags'),\n", " ('/rss.xml', 'RSS', 'icon-rss'),\n", " ('https://getnikola.com', 'About me', 'icon-user'),\n", " ('https://twitter.com/getnikola', 'My Twitter', 'icon-twitter'),\n", " ('https://github.com/getnikola', 'My Github', 'icon-github'),\n", " )\n", " }\n", "\n", "[2017-01-21T09:01:19Z] INFO: theme: Downloading 'https://themes.getnikola.com/v7/zen-jinja.zip'\n", "[2017-01-21T09:01:19Z] INFO: theme: Extracting 'zen-jinja' into themes/\n", "[2017-01-21T09:01:19Z] NOTICE: theme: This theme has a sample config file. Integrate it with yours in order to make this theme work!\n", "Contents of the conf.py.sample file:\n", "\n", " NAVIGATION_LINKS = {\n", " DEFAULT_LANG: (\n", " ('/index.html', 'Home', 'icon-home'),\n", " ('/archive.html', 'Archives', 'icon-folder-open-alt'),\n", " ('/categories/index.html', 'Tags', 'icon-tags'),\n", " ('/rss.xml', 'RSS', 'icon-rss'),\n", " ('https://getnikola.com', 'About me', 'icon-user'),\n", " ('https://twitter.com/getnikola', 'My Twitter', 'icon-twitter'),\n", " ('https://github.com/getnikola', 'My Github', 'icon-github'),\n", " )\n", " }\n", "\n", "[2017-01-21T09:01:19Z] NOTICE: theme: Remember to set THEME=\"zen-ipython\" in conf.py to use this theme.\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Organization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In addition to static content, I would like to have posts on my webpage describe research, projects, etc. These can be organized in \"sections\" by placing them in appropriate directories in [`posts`](mmfsite/forbes-group/posts) and then specifying the output directories in the `POSTS` variable in [`conf.py`](mmfsite/forbes-group/conf.py). One can then filter them, for example, with `{% for post in posts if post.section_name().lower() == \"highlights\" %}` in a template.\n", "\n", "I use this with a special template [`templates/research_highlights_list.tmpl`](mmfsite/forbes-group/themes/html5up-editorial/templates/research_highlights_list.tmpl) to format the research highlights on my index page." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Customization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Themes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we collect some notes about how themes work and can be customized. Themes are stored in the [`themes`](mmfsite/forbes-group/themes) directory. For example, [`themes/zen-ipython`](mmfsite/forbes-group/themes/zen-ipython). I have a separate repo for custom themes which I include in `_ext/forbes_group_website_theme` and then link into the [`themes`](mmfsite/forbes-group/themes)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A Nikola site can be customized in several ways:\n", "\n", "1. [`conf.py`](mmfsite/forbes-group/conf.py): Many customizations appear in this file, including some that might not be obvious:\n", " * `INDEX_READ_MORE_LINK`: This variable is used to customize the \"Read more\" link. We used this to modify these to look like a button matching the \"Editorial\" style.\n", " * `NAVIGATION_LINKS`: These appear in the side-bar, so you can specify the icons here (from [Font Awesome](http://fontawesome.io) if you use the `zen-*` themes).\n", " * `POSTS`/`PAGES`: Here you can specify which template files are used for posts and pages.\n", "2. Modify the templates. To do this, I found it easiest to copy all of the inherited template files into a new theme's `template` directory so I can see what is happening. Here are some important templates:\n", "\n", " * [`index.tmpl`](mmfsite/forbes-group/themes/html5up-editorial/templates/index.tmpl): Used for the index page collecting your blog posts.\n", " * [`post.tmpl`](mmfsite/forbes-group/themes/html5up-editorial/templates/post.tmpl): Used for the individual blog posts. This can be selected in `POSTS` variable of [`conf.py`](mmfsite/forbes-group/conf.py). These can also be controlled in the actual posts with the `template` variable.\n", " * [`story.tmpl`](mmfsite/forbes-group/themes/html5up-editorial/templates/story.tmpl): Used for static pages. This can be selected in `PAGES` variable of [`conf.py`](mmfsite/forbes-group/conf.py). These can also be controlled in the actual posts with the `template` variable." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `zen-ipython`\n", "This directory contains a file [`themes/zen-ipython/parent`](mmfsite/forbes-group/themes/zen-ipython/parent) that specify the parent theme - in this case [`themes/zen-jinja`](mmfsite/forbes-group/themes/zen-jinja). Thus, to find assets, etc. one might need to look in several places. Here is the full hierarchy for the [`themes/zen-ipython`](mmfsite/forbes-group/themes/zen-ipython) theme:\n", "\n", " * [`themes/zen-ipython`](mmfsite/forbes-group/themes/zen-ipython)\n", " * [`themes/zen-jinja`](mmfsite/forbes-group/themes/zen-jinja)\n", " * [`themes/base-jinja`](mmfsite/forbes-group/themes/base-jinja) (locate files with `nikola theme -g base-jinja`)\n", " * [`themes/base`](mmfsite/forbes-group/themes/base) (locate files with `nikola theme -g base`)\n", "\n", "The last two are pre-installed themes whose location on disk can be found using the specified command. I copied them into my site folder for easy reference.\n", "\n", "#### Icons\n", "The [`zen-ipython`](mmfsite/forbes-group/themes/zen-ipython) theme uses icons from [Font Awesome](http://fontawesome.io). To see the available icons and names, look at the [icon list](http://fontawesome.io/3.2.1/icons/) for the appropriate version ([version 3.2.1](http://fontawesome.io/3.2.1/) here). You can then specify the appropriate fonts in [`conf.py`](mmfsite/forbes-group/conf.py).\n", "\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Less/Sass\n", "\n", "The zen themes use [`less`], which they tell you in the [`Readme.md`](mmfsite/forbes-group/themes/zen-jinja/Readme.md) file can be enabled by setting `USE_BUNDLES = False` in [`conf.py`](mmfsite/forbes-group/conf.py) after installing the `lessc` compiler and `nikola plugin -i less`, however, you also need to rename/remove [`themes/zen-jinja/assets/css/main.cssmain.css`](mmfsite/forbes-group/themes/zen-jinja/assets/css/main.css) file or else you will get the following error (since it is also built with `lessc`...)\n", "\n", "```\n", "ERROR: Two different tasks can't have a common target.'output/assets/css/main.css' is a target for copy_assets:output/assets/css/main.css and build_less:output/assets/css/main.css.\n", "```\n", "\n", "Targets for `less` are specified in the file [themes/zen-jinja/less/targets](mmfsite/forbes-group/themes/zen-jinja/less/targets).\n", "\n", "I am using a custom theme which provides [`sass`](http://sass-lang.com) stylesheets. This requires installing the `sass` compiler and then one can use the `sass` plugin to generate appropriate CSS files. This theme was inheriting from the `zen-jinja` theme and so the `main.css` file was clashing with the previous file specified in [themes/zen-jinja/less/targets](mmfsite/forbes-group/themes/zen-jinja/less/targets). To resolve this, I added a custom less directory in the new theme with an empty [`themes/html5up-editorial/less/targets`](mmfsite/forbes-group/themes/html5up-editorial/less/targets) file. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Jinja2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here are some tips for working with Jinja2 (see the references section below for details.)\n", "\n", "* You can see the value of variables using code like this: `{{ post.tags|pprint }}` or if you need to `{{ post.__dict__.keys()|pprint }}`.\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Images" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One issue I had is how to include images in posts. The usual approach for notebooks is to include the images in a file relative to the notebook. For example, if the files are in a folder `images` then one can refer to this as\n", "\n", " ![Image](images/eli-francis-100644.jpg)\n", "\n", "There are two issues with this approach:\n", "\n", "1. Nikola will not copy these images to the output. This can be overcome by storing the files in the `images` folder at the root of your project, and then specifying where these should appear in the output by specifying `IMAGE_FOLDERS = {'images': 'images'}` (the default value) in your [`conf.py`] file. You can then symlink this file to your posts directory.\n", "2. The second issue is that this image will produce a link like this in the output:\n", "\n", " /highlights/prerequesites/images/eli-francis-100644.jpg\n", " \n", " I.e. this is a link relative to the post which would require a complicated set of non-standard `IMAGE_FOLDERS = {'images': 'images'}` mappings.\n", "\n", "The standard Nikola solution is to place the images in a `images/` folder in the top level of your project as above with `IMAGE_FOLDERS = {'images': 'images'}` in your [`conf.py`] file. Then refer with an absolute address:\n", "\n", " ![Image](/images/eli-francis-100644.jpg)\n", " \n", "Unfortunately, this breaks in the notebook rendering which cannot see higher-level directories. For example, if you start the Jupyter notebook server in the same directory as the post, then one would have to use the following absolute path in the notebook in order to see the image:\n", "\n", " ![Image](/tree/images/eli-francis-100644.jpg)\n", " \n", "This location could then be hacked with Nikola using `IMAGE_FOLDERS = {'images': 'tree/images'}`.\n", "\n", "### Solutions\n", "\n", "I see three possible solutions:\n", "\n", "1. Use the modified \"tree\" hack above:\n", "\n", " 1. Place images in \n", " \n", " images/eli-francis-100644.jpg\n", " \n", " 2. Symlink this to an images folder next to your posts.\n", " 3. Refer to your images as\n", "\n", " ![Image](/tree/images/eli-francis-100644.jpg)\n", " \n", " 4. Use the following mapping in your [`conf.py`] file:\n", " \n", " IMAGE_FOLDERS = {'images': 'tree/images'}\n", " \n", "2. Mirror the structure of your posts in your images directory. For example, if your posts are in `posts/highlights/my_post.ipynb`, then:\n", "\n", " 1. Place images in\n", " \n", " images/highlights/my_post/images/eli-francis-100644.jpg\n", "\n", " 2. Symlink these images to your posts directory:\n", " \n", " link -s ../../images/highlights/my_post/images .\n", "\n", " 3. Refer to images with a relative path:\n", " \n", " ![Image](images/eli-francis-100644.jpg)\n", " \n", " 4. Map the images to the root level so they are included in the relative path:\n", "\n", " IMAGE_FOLDERS = {'images': ''}\n", "\n", "3. Use the Nikola recommend approach of linking to an absolute path and extend the jupyter notebook server to properly redirect these requests.\n", "\n", " 1. Place images in\n", " \n", " images/eli-francis-100644.jpg\n", " \n", " 2. Refer to your images using an absolute path\n", "\n", " ![Image](/images/eli-francis-100644.jpg)\n", "\n", " 3. Run `jupyter notebook` from the top level (where `images` is) after installing and loading my notebook server extension [mmf_nikola_nbserver_extension](`mmfsite/nbserver_extensions/mmf_nikola_nbserver_extension`) (this is done in the file [`jupyter_notebook_config.py`](mmfsite/jupyter_notebook_config.py):\n", "\n", " pip install -e mmfsite/mmf_nikola_nbserver_extension\n", " jupyter serverextension enable mmf_nikola_nbserver_extension\n", "\n", "I am presently using the last approach.\n", "\n", "[`conf.py`]: mmfsite/forbes-group/conf.py\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Notebook Conversion" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The notebooks are converted to HTML through the `nbcovert` process. This can [be customized](http://nbconvert.readthedocs.io/en/latest/customizing.html) through templates or providing plugins. \n", "\n", "* The `'IPYNB_CONFIG'` variable in `conf.py` is passed to the [`HTMLExporter`](http://nbconvert.readthedocs.io/en/latest/external_exporters.html?highlight=HTMLExporter). To see possible options, run `jupyter nbconvert --help-all`. For example, I have added a preprocessor [`mmf_nikola_nbserver_extension.ArXivLinks`](mmfsite/forbes_group/mmf_nikola_nbserver_extension/mmf_nikola_nbserver_extension/__init__.py) which replaces references to preprints with a URL. This is enabled as follows in `conf.py`:\n", "\n", " IPYNB_CONFIG = {\n", " 'Exporter': {\n", " 'preprocessors': ['mmf_nikola_nbserver_extension.ArXivLinks']\n", " }\n", " }" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Plugins" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes you just can't seem to do what you want with the existing tools. One way of extending Nikola is to use a plugin. First check the [Nikola Plugins](https://plugins.getnikola.com) to see if you can find something, otherwise you can create your own in the [`plugins`](mmfsite/forbes-group/plugins) directory. To add a simple [reStructuredText directive](http://docutils.sourceforge.net/docs/howto/rst-directives.html), for example, you can install and copy the [book_figure plugin](https://plugins.getnikola.com/v7/book_figure/), which is a fairly simple plugin that creates a `book_figure` directive:\n", "\n", " nikola plugin -i book_figure\n", " mv plugins/book_figure plugins/mmf\n", " \n", "then edit the plugin.\n", "\n", "There are also some useful plugins: here is a list of the plugins I sometimes use:\n", "\n", "```bash\n", "nikola plugin -i less\n", "nikola plugin -i sass\n", "nikola plugin -i localsearch\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# References" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "People who have customized Nikola and describe the process:\n", "\n", "* [How I customized my Nikola-powered site](http://louistiao.me/posts/how-i-customized-my-nikola-powered-site/): A nice discussion about customizing a website powered with Nikola. Based on the `ipython` theme.\n", "* [Blogging with Nikola + Ipython + Git(Hub)](http://brunettoziosi.eu/posts/blogging-with-nikola-ipython-github/)\n", "\n", "Official Documentation:\n", "\n", "* [Creating a Site (Not a Blog)](https://getnikola.com/creating-a-site-not-a-blog-with-nikola.html)\n", "* [Nikola Theming](https://getnikola.com/theming.html)\n", "* [Nikola Internals](https://getnikola.com/internals.html) Describes the type of data available for use in templates etc.\n", "\n", "Jinja Templating:\n", "\n", "* [Template Designer Documentation](http://jinja.pocoo.org/docs/2.9/templates/)\n", "\n", "Some nice HTML and CSS templates:\n", "\n", "* [HTML5 UP](https://html5up.net): Some nice, responsive, and clean HTML and CSS templates. We have tried to massage one of these into a website." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python [conda env:blog]", "language": "python", "name": "conda-env-blog-py" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.12" }, "nikola": { "date": "2016-03-02 10:20:00 UTC-08:00", "description": "", "link": "", "slug": "nikola-install", "tags": "", "title": "Installing Nikola", "type": "text" }, "toc": { "base_numbering": 1, "nav_menu": { "height": "156px", "width": "252px" }, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": true, "toc_position": { "height": "1060px", "left": "0px", "right": "auto", "top": "130px", "width": "212px" }, "toc_section_display": "block", "toc_window_display": true } }, "nbformat": 4, "nbformat_minor": 1 }