Shopify Theme with Compass and Sass - sass

Does anyone have a workflow for developing Shopify themes with Compass and Sass? I am really close, I just need to figure out how to not make Sass barf on the CSS liquid tags.
Here's what I've got:
A sass/compass project in directory (ex:, "/newwebsite/)
A subdirectory containing my Shopify theme ("/newwebsite/newwebsite-theme/")
A Compass config.rb that points the css,_dir images_dir and javascripts_dir all to the them's assets folder ("/newwebsite/newwebsite-theme/assets/")
Compass watch on
shopify_theme gem also watch on, uploading theme files to shopify (https://github.com/Shopify/shopify_theme)
EDIT Sass interpolations (see anser below)
EDIT Compass callback to rename to .css.liquid
The problem: Compass barf's when you need to use Shopify's liquid templating tags, for example, a background image - example, background: url( "{{ "splash-1.jpg" | asset_url }}")
Does anyone know how to instruct Compass / Sass to spit out the liquid template tags as they are into the CSS? If I have that, then I have a solid workflow of editing Sass locally, and realizing the changes momentarily after on the shopify shop.
Thanks
EDIT:
By using Hopper's answer below for the liquid tags in Sass, and renaming the Compass output .css file to .css.liquid, I now have an instantaneous workflow for designing a Shopify theme with Compass and Sass!
Here is the code for the Compass callback that goes in the config.rb:
on_stylesheet_saved do |filename|
s = filename + ".liquid"
puts "copying to: " + s
FileUtils.cp(filename, s)
puts "removing: " + filename
end

I'm not familiar with Shopify or liquid tags, but I do know that in SASS you can use interpolations to output plain CSS as-is. For example, the SASS here:
.test {
background: url( #{'{{ "splash-1.jpg" | asset_url }}'} )
}
Would be compiled to:
.test {
background: url({{ "splash-1.jpg" | asset_url }}); }
Does that get you close to what you're looking for?

How do you keep Compass from barfing on liquid logic between properties? E.g. any time there's a liquid if statement I get errors, and using #{'...'} doesn't seem to help.
This is a test I can't get to work:
#container {
width:884px;
margin:0px auto;
min-height:500px;
position:relative;
padding:0 40px;
{% if settings.page_bg_transparent %}
background:transparent;
{% else %}
background:{{ settings.page_bg_color }};
{% endif %}
}
UPDATE weirdly, commenting liquid logic works:
#container {
width:884px;
margin:0px auto;
min-height:500px;
position:relative;
padding:0 40px;
/* {% if settings.page_bg_transparent %} */
background:transparent;
/* {% else %} */
background:#{'{{ settings.page_bg_color }}'};
/* {% endif %} */
}

For asset url you can also use SCSS custom functions.
Put this in your config.rb file
module Sass::Script::Functions
def shopify_image_url(string)
assert_type string, :String
Sass::Script::String.new("url({{'#{string.value}' | asset_url}})")
end
end
And then use it in your styles.scss like this
background: shopify_image_url('image.png');

I found it useful to remove the original output file after save so you don't have that extra, non liquid file floating in the assets dir.
on_stylesheet_saved do |filename|
s = filename + ".liquid"
puts "copying to: " + s
FileUtils.cp(filename, s)
puts "removing: " + filename
FileUtils.remove_file(filename)
end

Building on hopper's answer, for anyone using autoprefixer to process sass output, you would need to add an additional pair of quotes because url( {{ ... }} ) causes autoprefixer's parser to choke.
Do this:
background: url( "#{'{{ "splash-1.jpg" | asset_url }}'}" )
Which becomes this in the *.css.liquid file :
background: url( '{{ "splash-1.jpg" | asset_url }}' )

If you wish to preserve the ".scss.liquid" extension for the new responsive checkout use:
on_stylesheet_saved do |filename|
FileUtils.mv filename, "#{File.dirname(filename)}/#{File.basename(filename,'.*')}.scss.liquid"
end
It renames the files instead of copying and then removing.

I wrote an article describing the methods I used to get Compass and Sass working well with Shopify. This is the same approach of DOMUSNETWORK's answer. I go into a little more detail on file structure.
http://www.mealeydev.com/blog/shopify-and-sass/

This worked for me, partially - however I found that the Shopify Theme app a lot of times didn't want to upload my edited .css.liquid file, because apparently it didn't recognize that the file had been edited.
What solved it for me was to use the following code in my config.rb, instead of the code in the question above:
on_stylesheet_saved do |filename|
move_to = filename + ".liquid"
puts "Moving from #{filename} to #{move_to}"
FileUtils.mv(filename, move_to)
end

Shameless plug...
I think #nick is on the right track.
scss is better when it's compiled before sending to Shopify.
For others who find this answer, I think Quickshot is the tool you are looking for.
You will still need to interpolate for asset urls, but quickshot will automatically recompile your scss and upload the result to shopify in one step. Which also gives you the ability to use #include in your scss files.
http://quickshot.io/
https://github.com/internalfx/quickshot

Related

Is it possible to reuse hyperlink defined in another file in restructuredtext (or sphinx)

Suppose I have two files a.rst and b.rst in the same folder, and a.rst looks like this
.. _foo: http://stackoverflow.com
`foo`_ is a website
It seems using foo in b.rst is not allowed. Is there a way to define hyperlinks and use them in multiple files?
Followup
I used the extlinks extension as Steve Piercy suggested. Its implementation and docstring can be seen here on github.
In my case, I define wikipedia link in my conf.py
extlinks = {'wiki': ('https://en.wikipedia.org/wiki/%s', '')}
and in the .rst files, use them like
:wiki:`Einstein <Albert_Einstein>`
where Einstein will be displayed as a link to https://en.wikipedia.org/wiki/Albert_Einstein
There are at least four possible solutions.
1. repeat yourself
Put your complete reST in each file. You probably don't want that.
2. combined rst_epilog and substitution
This one is clever. Configure the rst_epilog value, in your conf.py along with a substition with the replace directive:
rst_epilog = """
.. |foo| replace:: foo
.. _foo: http://stackoverflow.com
"""
and reST:
|foo|_ is a website
yields:
<a class="reference external" href="http://stackoverflow.com">foo</a>
3. extlinks
For links to external websites where you want to have a base URL and append path segments or arguments, you can use extlinks in your conf.py:
extensions = [
...
'sphinx.ext.extlinks',
...
]
...
extlinks = {'so': ('https://stackoverflow.com/%s', None)}
Then in your reST:
:so:`questions/49016433`
Yields:
<a class="reference external"
href="https://stackoverflow.com/questions/49016433">
https://stackoverflow.com/questions/49016433
</a>
4. intersphinx
For external websites that are documentation generated by Sphinx, then you can use intersphinx, in your conf.py:
extensions = [
...
'sphinx.ext.intersphinx',
...
]
...
intersphinx_mapping = {
'python': ('https://docs.python.org/3', None),
}
Then in your reST:
:py:mod:`doctest`
Yields:
<a class="reference external"
href="https://docs.python.org/3/library/doctest.html#module-doctest"
title="(in Python v3.6)">
<code class="xref py py-mod docutils literal">
<span class="pre">doctest</span>
</code>
</a>
This might come a bit late but I have found a solution that works very neatly for me and it is not among the answers already given.
In my case, I create a file with all the links used in my project, save it as /include/links.rst, and looking something like:
.. _PEP8: https://www.python.org/dev/peps/pep-0008/
.. _numpydoc: https://numpydoc.readthedocs.io/en/latest/format.html
.. _googledoc: https://google.github.io/styleguide/pyguide.html
Then there are the files a.rst and b.rst looking like:
.. include:: /include/links.rst
File A.rst
##########
Click `here <PEP8_>`_ to see the PEP8 coding style
Alternatively, visit either:
- `Numpy Style <numpydoc_>`_
- `Google Style <googledoc_>`_
and
.. include:: /include/links.rst
File B.rst
##########
You can visit `Python's PEP8 Style Guide <PEP8_>`_
For docstrings, you can use either `Numpy's <numpydoc_>`_ or `Google's <googledoc_>`_
respectively.
The produced output for both cases is:
and
respectively.
Moreover, I would like to emphasize the fact of which I was actually really struggling to achieve, to use different names (displayed text) for the same link at different locations and which I have achieved with the double _, one inside the <..._> and another outside.
This is another solution: it is a bit hacky and a little bit different respect to the officially supported way to share external links.
First complete the Setup then:
in conf.py add the commonlinks entry in extensions
in conf.py configure the map of common links:
For example:
extensions = [
...,
'sphinx.ext.commonlinks'
]
commonlinks = {
'issues': 'https://github.com/sphinx-doc/sphinx/issues',
'github': 'https://github.com'
}
Then in .rst files you can do these:
The :github:`_url_` url is aliased to :github:`GitHub` and also to :github:`this`
Setup
All that is needed is to copy into sphinx/ext directory the file commonlinks.py:
# -*- coding: utf-8 -*-
"""
sphinx.ext.commonlinks
~~~~~~~~~~~~~~~~~~~~~~
Extension to save typing and prevent hard-coding of common URLs in the reST
files.
This adds a new config value called ``commonlinks`` that is created like this::
commonlinks = {'exmpl': 'http://example.com/mypage.html', ...}
Now you can use e.g. :exmpl:`foo` in your documents. This will create a
link to ``http://example.com/mypage.html``. The link caption depends on the
role content:
- If it is ``_url_``, the caption will be the full URL.
- If it is a string, the caption will be the role content.
"""
from six import iteritems
from docutils import nodes, utils
import sphinx
from sphinx.util.nodes import split_explicit_title
def make_link_role(base_url):
def role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
text = utils.unescape(text)
if text == '_url_':
title = base_url
else:
title = text
pnode = nodes.reference(title, title, internal=False, refuri=base_url)
return [pnode], []
return role
def setup_link_roles(app):
for name, base_url in iteritems(app.config.commonlinks):
app.add_role(name, make_link_role(base_url))
def setup(app):
app.add_config_value('commonlinks', {}, 'env')
app.connect('builder-inited', setup_link_roles)
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
To locate the sphinx installation directory one way is:
$ python 3
> import sphinx
> sphinx
<module 'sphinx' from '/usr/local/lib/python3.5/dist-packages/sphinx/__init__.py'>
then:
% cp commonlinks.py /usr/local/lib/python3.5/dist-packages/sphinx/ext

I'm having trouble building color swatches using the json export feature of Herman for sassDocs

Questions:
I have a sass-to-json.css where the only think printed is the comment that exports from #include herman-export;. Do I need to manually un-comment that JSON and/or rename the file to have a json extension?
My .sassdocrc file:
dest: public/docs
theme: node_modules/sassdoc-theme-herman
verbose: true
herman:
sass:
sass.jsonfile: public/json/sass-to-json.css
Then my sass-to-json.scss file just has the two imports where herman code exists, and the export mixin. (I'm not sure if all of this is necessary, but the json compiles correctly)
#import "utilities";
#import "base/colors";
#include herman-export;
compiles to sass-to-json.css. I have tried removing the comment so it's valid json and renaming the file to .json. But I get the same result, which is that herman compiles the page without the swatches, and without errors:
/*! json-encode: {"colors": {"theme": {"shade": "#16161e", "tint": "#f0f0fb", "dark-grey": "#393946", "grey": "#7d8c9c", "white": "#fff", "black": "#000", "blue": "#0c55b7", "green": "#3fbb26", "yellow": "#e7b60a", "red": "#e71b46"}}} */
The relevant bits of my colors.scss file:
/// #group color
/// #colors theme
$theme: (
'shade': #16161e,
'tint': #f0f0fb,
'dark-grey': #393946
);
#include herman-add('colors', 'theme', $theme);
Your Sass (and usage of herman-add and herman-export) looks great! No need to mess with the contents of the generated sass-to-json.scss file; it's supposed to be a valid Sass comment, and Herman itself will take care of parsing it as valid JSON.
The docs are a bit unclear, but the relevant option here is jsonfile nested under the sass option, not sass.jsonfile. So for example:
dest: public/docs
theme: herman
verbose: true
herman:
sass:
jsonfile: public/json/sass-to-json.css
(Note that you can also just specify herman as the theme, and SassDoc will automatically look for node_modules/sassdoc-theme-herman.)

Removing the view source link when using Read The Docs & Sphinx with ReadTheDocs Theme

Is there any way to remove the "View page source" link from a sphinx generated read the docs theme page?
There is a similar question here and it recommends finding the breadcrumbs file, but I can't find one
In your conf.py file, try setting the variable html_show_sourcelink to False,
html_show_sourcelink = False
If it does not exist, just create it. Then, compile again the project,
$ make html
Don't be fooled by the configuration. You can see the source code.
In fact, from the HTML theming support of Sphinx, it introduced that the structure of a theme should look like this.
[theme]
inherit = base theme
stylesheet = main CSS name
pygments_style = stylename
sidebars = localtoc.html, relations.html, sourcelink.html, searchbox.html
...
here is site-packages/sphinx_rtd_theme/theme.conf
[theme]
inherit = basic
stylesheet = css/theme.css
pygments_style = default
So we know that its sidebars completely inherited from basic.
What is basic? One of the themes of the sphinx.
site-packages/sphinx/theme/ {basic, nature...}
The contents of site-packages/sphinx/themes/basic/sourcelink.html
...
{%- if show_source and has_source and sourcename %}
<div role="note" aria-label="source link">
<h3>{{ _('This Page') }}</h3>
<ul class="this-page-menu">
<li><a href="{{ pathto('_sources/' + sourcename, true)|e }}"
rel="nofollow">{{ _('Show Source') }}</a></li>
</ul>
</div>
{%- endif %}
(If you are confused with this format, please reference here: jinja))
And then, we know that show if and only if the show_source, has_source, sourcename all the True.
What is show_source, has_source, sourcename ?
If your format is HTML, then it's coming from: sphinx.builders.html StandaloneHTMLBuilder
Among them, he created a variable globalcontext, see below:
class StandaloneHTMLBuilder(Builder):
...
def prepare_writing(...):
...
self.globalcontext = {
'has_source': self.config.html_copy_source,
'show_source': self.config.html_show_sourcelink,
}
...
...
def get_doc_context(...):
...
# the name for the copied source
if self.config.html_copy_source:
sourcename = docname + source_suffix
if source_suffix != self.config.html_sourcelink_suffix:
sourcename += self.config.html_sourcelink_suffix
else:
sourcename = ''
Click the link if you want to see the full code
prepare_writing
get_doc_context
Now, I think you already get it.
has_source is html_copy_source
show_source is html_show_sourcelink
and sourcename = ... if html_copy_source else ''
So, the close way has two, both ok.
html_copy_source = False (since has_source + html_copy_source)
html_show_sourcelink = False (since show_source + htm_show_sourcelink )
(or 3. both eq False ...)
It doesn't work in my side with #lucasrodesg's answer, my Sphinx vertion is 1.8.2, I just removed 'sphinx.ext.viewcode' of extensions variable in the conf.py and worked. Just like in the following code, uncomment the last line.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.mathjax',
# 'sphinx.ext.viewcode',]

Convert SASS to CSS using SASS gem

I am trying to create a CSS file from SASS file.
I tried to do this at first.
sass_filename = "#{Rails.root}/app/assets/stylesheets/application.sass"
css = Sass::Engine.for_file(sass_filename).render
File.open("#{render_path}/stylesheets/application.css", "wb") {|f| f.write(css) }
I got error wrong number of arguments (1 for 2) on Sass::Engine.for_file() because I didn't put anything for options field.
I am not sure how I can set the options field.
I tried
css = Sass::Engine.for_file(sass_filename, :syntax => :sass).render
but I got undefined method[]' for nil:NilClass` error.
How do I set the default option for converting SASS to CSS ?
If you are not passing any options try using an empty hash, e.g. '{}', for options:
sass_filename = "#{Rails.root}/app/assets/stylesheets/application.sass"
css = Sass::Engine.for_file(sass_filename, {}).render
File.open("#{render_path}/stylesheets/application.css", "wb") {|f| f.write(css) }

SASS: syntax errors when using shorthand syntax

My scss file is this:
#import "compass/typography/lists/bullets";
.view-content ul
+no-bullets
This gives me an error on the page:
Syntax error: Invalid css after " +no-bullets": expected "{", was ""
However, when the rule looks like this:
.view-content ul {
#include no-bullets;
}
then it's OK and bullets are gone.
But I like the shorthand notation, how to enable using it?
You're right, I found the related documentation.
I tried the following and it works.
Then, I tried your and it didn't work until I remove the trailing ; on the import instruction.
#import "compass/typography/lists/bullets"
.view-content ul
+no-bullets
The following works with Compass 0.12.2. Try removing the trailing ; on the import instruction.

Resources