Dynamic styles for different user - ruby-on-rails

I need dynamic styles for each user. The problem is such that it is possible to choose between two themes, one static and the other user can change. After change current user theme value will set to sass variable and need precompile. How I can do it?

It's better to rely on pure CSS features in this one rather than compile your SCSS on each request (which will be very inefficient).
Given this base SCSS file:
.base-theme {
.color-main {
color: $blue-lighter;
}
// and so on
}
You can use this like this:
<p class="color-main"> ... </p>
Based on settings stored in the database you can generate an alternative
theme like so:
<style>
.alt-theme .color-main {
color: <%= current_user.colors.main %>;
}
</style>
and apply them later like so:
<body class="<%= user.has_theme?? 'alt-theme' : 'base-theme' %>">...</body>

Related

Find image-url specified in css content from Capybara

I have specified the image-url in css file rather than in img tag in html. That is because I have one layout for many stylesheets in my Rails application. Now I am not able to find that image from Capybara. How can I do that?
html
<div id="company_logos">
<div id="first_logo"></div>
<div id="second_logo"></div>
</div>
css
#company_logos {
/* css for parent */
}
#first_logo {
content: image-url(company_name/company_logo.png);
}
#second_logo {
display: none;
}
capybara_test.rb
within('#company_logos') do
within('#first_logo') do
assert find('content')['src'].include? "company_name/first_logo"
end
end
I am getting the error: unable to find content. How can I rectify this so that capybara finds the content image-url?
In your test you're trying to check the elements style. One way to do that is via the style filter which can be used with any element finder/matcher/assertion in Capybara
assert_selector(:css, '#first_logo', style: { content: /company_name\/first_logo/ })
If you've already found the element you want to verify the style on (element) then you can use assert_matches_style
assert_matches_style(element, content: /company_name\/first_logo/) # assuming you're using minitest
Note: this all assumes you're using a driver which processes CSS (ie NOT the rack_test driver)

Slim templates and TailwindCSS use ' : ' in class declaration

TailwindCSS is looking like a great frontend tool but I'm wondering how to use it with the Rails Slim template language?
For example:
<div class="bg-red-500 sm:bg-green-500 md:bg-blue-500 lg:bg-pink-500 xl:bg-teal-500"></div>
If I run it through HTML2SLIM I get this recommendation:
.bg-red-500.sm:bg-green-500.md:bg-blue-500.lg:bg-pink-500.xl:bg-teal-500
Which produces the following HTML:
<div class="bg-red-500 sm">
<bg-green-500 class="md">
<bg-blue-500 class="lg">
<bg-pink-500 class="xl">
<bg-teal-500></bg-teal-500>
</bg-pink-500>
</bg-blue-500>
</bg-green-500>
</div>
It seems that the colon ':' is interperted as multiple html elemments. Im wondering if there's a way around this? I'd love to use Slim with TailwindCSS.
So far I've made some progress using Rails' content_tag:
= content_tag :span, 'Accounts', class: 'invisible md:visible lg:visible'
But I can only go so far with this.
Another option is to configure Tailwind to use another separator as documented here: https://tailwindcss.com/docs/configuration/#separator
// tailwind.config.js
module.exports = {
separator: "_",
}
Then you could do .sm_bg-green-500 and so on.
There are also class names like .w-1/2 in Tailwind, that are not affected by this setting. You could add custom class names to work around that, e.g.
// tailwind.config.js
module.exports = {
…
theme: {
extend: {
width: {
"1-of-2": "50%"
}
}
}
}
and then use .w-1-of-2.
It's just not possible to have these colons in the class shorthand notation. You can do the following though
div class="bg-red-500.sm::bg-green-500.md:bg-blue-500.lg:bg-pink-500.xl:bg-teal-500"
which results in the desired HTML:
<div class="bg-red-500 sm:bg-green-500 md:bg-blue-500 lg:bg-pink-500 xl:bg-teal-500"></div>

div tag class attribute contains lot of strings and cannot be replaced with css string definition string

I am trying to develop an UI and the first step is to create CssLayout. Each CssLayout component is added hierarchically with and many CssLayout component.
The problem is when i run the application and inspect the div tags, the class attribute has extra strings that needs to be removed.
<div class="v-csslayout v-layout v-widget .content-container v-
csslayout-.content-container v-has-width v-has-height" style="width: 100%;
height: 100%;"><div class="v-csslayout v-layout v-widget .inner-content-
container v-csslayout-.inner-content-container"></div></div>
and what I need is
<div class=".content-container">
<div class=".inner-content-container">
</div>
</div>
Java Code:
#StyleSheet("{css/spreadjsdefault.css}")
public class SpreadJSWidget extends CssLayout {
/**
*
*/
public SpreadJSWidget() {
super();
addStyleName(".content-container");
CssLayout mainBox = new CssLayout();
mainBox.addStyleName(".inner-content-container");
addComponent(mainBox);
}
spreadjsdefault.css (They are empty for now)
.content-container
{
}
.inner-content-container
{
}
Please advice !
Two things:
In order to be able to properly match the css rules, you have to omit the leading . when adding the style name, i.e. addStyleName("contentContainer"). This way, the css elements will match your style definition.
Css classes like v-csslayout are default classes defined by vaadin used by the default themes to provide a basic layout. They are there by default and can't (and actually shouldnt) be removed entirely. What you can do, however, is to define and overwrite these rules yourself. What's important: Either way, your custom classes will still match when you define them in your style sheet and can overwrite the default theming.

Reveal.js: Add fragments inside code

I've got a presentation running with reveal.js and everything is working. I am writing some sample code and highlight.js is working well within my presentation. But, I want to incrementally display code. E.g., imagine that I'm explaining a function to you, and I show you the first step, and then want to show the subsequent steps. Normally, I would use fragments to incrementally display items, but it's not working in a code block.
So I have something like this:
<pre><code>
def python_function()
<span class="fragment">display this first</span>
<span class="fragment">now display this</span>
</code></pre>
But the <span> elements are getting syntax-highlighted instead of read as HTML fragments. It looks something like this: http://imgur.com/nK3yNIS
FYI without the <span> elements highlight.js reads this correctly as python, but with the <span>, the language it detects is coffeescript.
Any ideas on how to have fragments inside a code block (or another way to simulate this) would be greatly appreciated.
To make fragments work in code snippets, you can now use the attribute data-noescape with the <code> tag
Source: Reveal.js docs
I got this to work. I had to change the init for the highlight.js dependency:
{ src: 'plugin/highlight/highlight.js', async: true, callback: function() {
[].forEach.call( document.querySelectorAll( '.highlight' ), function( v, i) {
hljs.highlightBlock(v);
});
} },
Then I authored the section this way:
<section>
<h2>Demo</h2>
<pre class="stretch highlight cpp">
#pragma once
void step_one_setup(ofApp* app)
{
auto orbit_points = app-><span class="fragment zoom-in highlight-current-green">orbitPointsFromTimeInPeriod</span>(
app-><span class="fragment zoom-in highlight-current-green">timeInPeriodFromMilliseconds</span>(
app->updates.
<span class="fragment zoom-in highlight-current-green" data->milliseconds</span>()));
}
</pre>
</section>
Results:
I would try to use multiple <pre class="fragment">and change manually .reveal pre to margin: 0 auto; and box-shadow: none; so they will look like one block of code.
OR
Have you tried <code class="fragment">? If you use negative vertical margin to remove space between individual fragments and add the same background to <pre> as <code> has then you get what you want.
Result:

Rails: Is it possible to reference a instance variable (like #user.color_preferred) with an interpolated string?

I'm trying to change the background color with the field color_preferred defined in the model User.
/* file example.css.scss.erb */
$color: <%= #user.color_preferred %>;
body {
background-color: $color;
color: #333;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px; }
Is it possible to access the ruby instance variables from sass files?
Tk.
Rafa.
I believe, it's not possible. Sass gets compiled on deployment (in Rails 3.1), afterwards it is a static file. It would not make any sense, either. The css files should be independent of the user and be cachable for a long time.
Why don't you insert a style tag inside of your layout and overwrite the default style defined inside your css, if the user has chosen a preferred color?
Yes. You can do this by extending Sass::Script::Functions. Simply create a ruby file, add this bit in, and then load it into your script's environment (i.e. /config/initializers/):
module Sass::Script::Functions
def var(name)
assert_type name, :String, :name
#environment.var(name.value)
end
declare :var, :args => [:string]
end
Then you can do stuff like this:
$button-primary-bg: #000;
$button-secondary-bg: #123;
$button-tertiary-bg: #abc;
$button-names: (primary, secondary);
#each $name in $names {
.button-#{$name} { background: var("button-#{$name}-bg"); }
}
It is possible but it involves hacking through Sass and going deep into it. The better way is like iGel said, create different "themes" and include that to your body depending on the user's preference.
Say you have a main.css and some theming colors(say a different body-background depending on the user's choice)
= stylesheet_include_tag 'main'
= stylesheet_include_tag "#{#user.color_preferred}"
then you have some colors premade like blue.sass, red.sass, green.sass, etc.
it is easy to generate these as you can just use a variable like you did in your example except that you have to reproduce it to support different colors.

Resources