Instantly share code, notes, and snippets.

Embed
What would you like to do?
Ember Theming
import Ember from 'ember';
export default Ember.Component.extend({
theme: Ember.inject.service()
// ...
});
import Ember from 'ember';
export default Ember.Route.extend({
theme: Ember.inject.service(),
// set theme to "second" when hitting route
beforeModel: function() {
this._super(...arguments);
this.get('theme').setTheme('second');
},
actions: {
// set theme to "first" when leaving route
willTransition: function() {
this.get('theme').setTheme('first');
this._super(...arguments);
}
}
});
<div class="my-awesome-class" data-theme="{{theme.name}}">
stuff goes here
</div>
// usage:
div.my-awesome-class {
@include theme('color', 'primary');
}
// results in the output:
div.my-awesome-class[data-theme="default-first"] {
color: #58b15f;
}
div.my-awesome-class[data-theme="default-second"] {
color: #287f6e;
}
import Ember from 'ember';
export default Ember.Service.extend({
base: 'default',
theme: 'first',
// the property used as a reference for styles
name: Ember.computed('base', function() {
const base = this.get('base');
const theme = this.get('theme');
return `${base}-${theme}`;
}),
// update things that may be using data-theme
themeChanged: Ember.observer('base', 'theme', function() {
this.notifyPropertyChange('name');
}),
// set the base theme for the application
setBase: function(base) {
this.set('base', Ember.isEmpty(base) ? 'default' : base);
},
// set theme to use within base theme
setTheme: function(theme) {
this.set('theme', Ember.isEmpty(theme) ? 'first' : theme);
}
});
// theme map
$themes: (
default: (
first: (
primary: #58b15f,
secondary: #e3f0d8
),
second: (
primary: #287f6e,
secondary: #83e5d2
)
)
);
// if theme service exists as addon - allow 3rd parties to merge into themes.
@if variable-exists(theme-additional) {
$themes: map-merge($themes, $theme-additional);
}
@mixin apply-theme() {
@each $base, $attributes in $themes {
@each $section, $values in $attributes {
$name: "#{$base}-#{$section}";
&[data-theme="#{$name}"] {
}
}
}
}
// helper for SASS files to apply theme values to an element.
// usage: @include theme('color', 'primary');
@mixin theme($cssAttribute, $themeValue) {
@each $base, $attributes in $themes {
@each $section, $values in $attributes {
$name: "#{$base}-#{$section}";
&[data-theme="#{$name}"] {
@if $cssAttribute == "background" and $themeValue == "bg-image" {
$url: map-get($values, $themeValue);
#{$cssAttribute}: url($url) repeat-x;
} @else if $cssAttribute == "background" and $themeValue == "icon" {
$url: map-get($values, $themeValue);
#{$cssAttribute}: url($url) no-repeat;
} @else {
#{$cssAttribute}: map-get($values, $themeValue) !important;
}
// ...
}
}
}
}
// helper for more advanced theming.
// usage: @include theme-advanced('border', '', 'accent', '1px solid');
@mixin theme-advanced($cssAttribute, $before, $themeValue, $after) {
@each $base, $attributes in $themes {
@each $section, $values in $attributes {
$name: "#{$base}-#{$section}";
&[data-theme="#{$name}"] {
#{$cssAttribute}: #{$before} map-get($values, $themeValue) #{$after};
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment