Conditionally load Sass stylesheets with variable overrides - ruby-on-rails

In our app, we have different clinics, and all patient pages are nested under a clinic, which has branding. We have 100+ clinics, so I'd rather not have something like = stylesheet_link_tag #{#clinic.name}_theme in my application.html.haml file, and have a theme file that's like
// clinic_a.css.sass
a
color: red
// clinic_b.css.sass
a
color: blue
I'd rather use color variables throughout all my Sass files, then define those variables in separate sheets that get called based on the clinic (found by the params, say). So:
// application.css.sass
a
color: $link_color
h1
color: $neutral_color
// clinic_a.css.sass
$link_color: #faa
$neutral_color: #ccc
// clinic_b.css.sass
$link_color: #96c7c7
$neutral_color: #bababa
The issue is, it seems like the variables have to come first in the asset pipeline, so they'd have to be declared before the other files in my application.css.sass file. But obviously, that file doesn't have access to params or anything.
How can I decide which variables file to load based on params, which will then get evaluated all over my application.css.sass file, and files included in that?
Edit
Just to be clear, this would have to work with Rails's asset pipeline.

I wouldn't load different stylesheets, I would use the #if function inside sass to conditionally assign variables:
EXAMPLE
p {
#if 1 + 1 == 2 { border: 1px solid; }
#if 5 < 3 { border: 2px dotted; }
#if null { border: 3px double; }
}

Related

Web components with vaadin and rollup with svelte: Primary button ignores theme attribute

Maybe someone tried this before and is able to give me a hint.
I have used normal svelte setup (mentioned in the main page) which scaffolds the app;
npx degit sveltejs/template my-svelte-project
I wanted to use vaadin web components in Svelte. I've installed it;
npm install #vaadin/vaadin
the code of main.ts:
<script lang="ts">
import '#vaadin/button/theme/material'
</script>
<main>
<vaadin-button theme="primary">Primary</vaadin-button>
<vaadin-button theme="secondary">Sec</vaadin-button>
</main>
<style>
main {
text-align: center;
padding: 1em;
max-width: 240px;
margin: 0 auto;
}
#media (min-width: 640px) {
main {
max-width: none;
}
}
</style>
And the thing is that it almost works :) The buttons are styled, I can click on them but... the theme is ignored;
The primary should have a background color like stated in docs;
https://vaadin.com/docs/latest/ds/components/button/#styles
any idea???
This is happening because of how Svelte sets data on custom elements. If a property exists on the element with the same name as the attribute you set, Svelte will set the property instead of the attribute. Otherwise, it will fall back to the attribute. So, the following...
<vaadin-button theme="primary">Primary</vaadin-button>
...gets compiled to something like:
button.theme = "primary";
Normally this works great, especially when setting array and object properties. However, the vaadin-button styles expect the theme attribute to be set, not the property. Because Svelte sets the property instead, the styles don't apply.
:host([theme~="primary"]) {
background-color: var(--_lumo-button-primary-background-color, var(--lumo-primary-color));
color: var(--_lumo-button-primary-color, var(--lumo-primary-contrast-color));
font-weight: 600;
min-width: calc(var(--lumo-button-size) * 2.5);
}
I would argue that this is a Vaadin bug - if you expose an attribute and a property for the same data, it shouldn't matter which one the consumer sets. Setting the property should have the same effect as setting the attribute. A quick way to fix this would be for vaadin-button to reflect the theme property, so that setting theme also sets the attribute. Here's how to do that in Lit.
However, that change requires the component library authors to implement it. As a consumer of the library, you can also work around this in Svelte by using an action to force Svelte to set the attribute instead.
<script>
import "#vaadin/button";
function setAttributes(node, attributes) {
for (const [attr, value] of Object.entries(attributes))
node.setAttribute(attr, value);
}
</script>
<main>
<vaadin-button use:setAttributes={{ theme: "primary" }}>Primary</vaadin-button>
<vaadin-button>Normal</vaadin-button>
</main>
I wrote an article about this behavior and other workarounds at CSS-Tricks, if you want a more in-depth explanation.
You seem to be importing the Material theme version of the Button component. The "primary" theme variant is only available if you use the default Lumo theme. To import that, use import '#vaadin/button';
For the Material theme, you can use the "outlined" and "contained" theme variants instead: https://cdn.vaadin.com/vaadin-material-styles/1.3.2/demo/buttons.html

How to print a Component in Vaadin?

I have been struggling for sometime now, trying to find ways to print out/generate document using vaadin.
i have tried using the below code but this prints all the components. I wanted to print only a particular form or layout.
UI.getCurrent().getElement().executeJs("print();")
Can some one guide me?
You'll need some CSS (similar to the approach mentioned here) that will hide everything when printing is invoked, except for the Layout or Component that needs to be printed.
For example, assuming you have the following two DIVs in your view:
Div printable = new Div(new Span("printable"));
Div nonPrintable = new Div(new Span("nonPrintable"));
You can give one of those a classname:
printable.addClassName("printable");
Then, you would add the following CSS to the global scope:
#media print {
body, body * {
visibility: hidden;
}
.printable, .printable * {
visibility: visible;
}
.printable {
position: absolute;
left: 0;
top: 0;
}
}
Note, in a Vaadin 14 project, the previous CSS is most easily incorporated using the #CssImport annotation. For example, the following annotations can be added to one of your Java classes:
#CssImport("./shared-styles.css")
Then under the directory {projecr-root-directory}/frontend, you'd need to create shared-styles.css and place the aforementioned styling there.

Dynamic styles for different user

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>

Using qTip2 with Ruby on Rails

I found this wonderfull tooltip called qTip2. Loving it so far but has gotten myself into a problem using it.
I was able to install and get qTip2 running with my Rails 3.1 setup. However I'm running into a problem when I'm using qTip2's ajax functionality.
qTip2 ajax request requires a link to the script to be executed before displaying it in the tooltip content div (which is automatically generated by qTip2). You can look at the code I'm referring to here.
http://www.craigsworks.com/projects/qtip2/demos/#ajax
The problem with it is that it does not really go well with RoR. An ajax request declared using RoR is more explicit, where I can explicitly tell rails which div id I would like to update.
Given the following circumstances I needed to do the following things:
the tooltip content must be dynamic
I needed to use the qTip2 ajax functionality so that I could create a custom layout for the tooltip content.
I did try the followings though:
Put the html snippet to be loaded to the content div in the public folder. The content loaded with the right format but I can't have dynamic content. html.erb files didn't seem to work in this folder. Is there any alternative to this folder that would work but with dynamic content?
Tried to use qTip2 ajax request with RoR but was not successful. What I did was I tried to explicitly define the ajax update id in the .js respond file (going through the controller and views etc.). But figuring out the exact id that was generated by qTip2 plugin was a little too overwhelming for me.
here is what I have
html
<a id="editor1" href="/deals_details.html.erb">
javascript
$(document).ready(function()
{
$('#editor1').each(function()
{
$(this).qtip(
{
content: {
text: '<img class="throbber" src="/assets/throbber.gif" alt="Loading..." />',
ajax: {
/*once: false*/
url: $(this).attr('href')
},
title: {
text: 'qTip2 Test',
button: true
}
},
position: {
at: 'center',
my: 'center',
viewport: $(window),
},
show: {
event: 'click',
solo: true
},
hide: 'unfocus',
style: {
classes: 'ui-tooltip-wiki ui-tooltip-light ui-tooltip-shadow'
}
})
})
// Make sure it doesn't follow the link when we click it
.click(function(event) { event.preventDefault(); });
});
CSS
.ui-tooltip-wiki{
max-width: 440px;
}
.ui-tooltip-wiki .ui-tooltip-content{
padding: 10px;
line-height: 12.5px;
}
.ui-tooltip-wiki h1{
margin: 0 0 7px;
font-size: 1.5em;
line-height: 1em;
}
.ui-tooltip-wiki img{ padding: 0 10px 0 0; }
.ui-tooltip-wiki p{ margin-bottom: 9px; }
.ui-tooltip-wiki .note{ margin-bottom: 0; font-style: italic; color: #888; }
Please help me!! :) Apology if this post looks stupid, this is my first question on stackoverflow.
I think you're making it too complicated. The qTip ajax functionality simply requests a URL, and the return value is HTML content within a div tag. If you look at the source of the demo you mentioned, you'll see a request for http://www.craigsworks.com/projects/qtip2/data/burrowingowl.php. If you look at what that produces, it is simply a div tag with some content (the style looks different because it is further transformed by the page's CSS).
So the question becomes: can you provide your dynamic content in a div in response to a URL in Rails? Of course! Perhaps you want to set up a SnippetController with a show action and then using pretty standard Rails conventions/routes your URL might be /snippet/show/[ID] and you simply have the view produce the required div content.

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