Skip to content

Commit

Permalink
feat: add theme support (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
mariobuikhuizen authored Apr 23, 2020
1 parent 46b310a commit af6b78c
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 4 deletions.
37 changes: 37 additions & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,43 @@ In some widgets icons are specified by setting an attribute:

See `materialdesignicons.com/4.5.95 <https://cdn.materialdesignicons.com/4.5.95/>`_ for a list of available icons.

Themes
------

To enable the dark theme:

.. code-block:: python
v.theme.dark = True
To customize the themes:

.. code-block:: python
v.theme.themes.light.primary = '#b71c1c'
v.theme.themes.dark.primary = '#a71c1c'
Also, the `pre-defined material colors <https://vuetifyjs.com/en/styles/colors/#sass-color-pack>`_ are supported:

.. code-block:: python
v.theme.themes.light.primary = 'colors.teal'
v.theme.themes.light.secondary = 'colors.teal.lighten4'
Available theme properties:

- primary
- secondary
- accent
- error
- info
- success
- warning
- anchor

Summary
-------

Expand Down
70 changes: 70 additions & 0 deletions ipyvuetify/Themes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from ipywidgets import Widget
from traitlets import Unicode, Bool
from ._version import semver


class Themes:
def __init__(self):
self.light = ThemeColors(
_theme_name='light',
primary='#1976D2',
secondary='#424242',
accent='#82B1FF',
error='#FF5252',
info='#2196F3',
success='#4CAF50',
warning='#FB8C00')

self.dark = ThemeColors(
_theme_name='dark',
primary='#2196F3',
secondary='#424242',
accent='#FF4081',
error='#FF5252',
info='#2196F3',
success='#4CAF50',
warning='#FB8C00')


class Theme(Widget):
_model_name = Unicode('ThemeModel').tag(sync=True)

_model_module = Unicode('jupyter-vuetify').tag(sync=True)

_view_module_version = Unicode(semver).tag(sync=True)

_model_module_version = Unicode(semver).tag(sync=True)

dark = Bool(False).tag(sync=True)

def __init__(self):
super().__init__()

self.themes = Themes()


class ThemeColors(Widget):

_model_name = Unicode('ThemeColorsModel').tag(sync=True)

_model_module = Unicode('jupyter-vuetify').tag(sync=True)

_view_module_version = Unicode(semver).tag(sync=True)

_model_module_version = Unicode(semver).tag(sync=True)

_theme_name = Unicode().tag(sync=True)

primary = Unicode().tag(sync=True)
secondary = Unicode().tag(sync=True)
accent = Unicode().tag(sync=True)
error = Unicode().tag(sync=True)
info = Unicode().tag(sync=True)
success = Unicode().tag(sync=True)
warning = Unicode().tag(sync=True)
anchor = Unicode(None, allow_none=True).tag(sync=True)


theme = Theme()

__all__ = ['theme']
1 change: 1 addition & 0 deletions ipyvuetify/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .Html import Html # noqa: F401
from .VuetifyTemplate import VuetifyTemplate # noqa: F401
from .generated import * # noqa: F401, F403
from .Themes import theme # noqa: F401


def _jupyter_nbextension_paths():
Expand Down
100 changes: 100 additions & 0 deletions js/src/Themes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/* eslint camelcase: off */
import { WidgetModel } from '@jupyter-widgets/base';
import colors from '@mariobuikhuizen/vuetify/lib/util/colors';
import vuetify from './plugins/vuetify';

export class ThemeModel extends WidgetModel {
defaults() {
return {
...super.defaults(),
...{
_model_name: 'ThemeModel',
_model_module: 'jupyter-vuetify',
_view_module_version: '0.1.11',
_model_module_version: '0.1.11',
dark: null,
},
};
}

constructor(...args) {
super(...args);

if (!vuetify) {
return;
}
vuetify.framework.theme.dark = this.get('dark');
this.on('change:dark', () => {
vuetify.framework.theme.dark = this.get('dark');
});
}
}

ThemeModel.serializers = {
...WidgetModel.serializers,
};

export class ThemeColorsModel extends WidgetModel {
defaults() {
return {
...super.defaults(),
...{
_model_name: 'ThemeColorsModel',
_model_module: 'jupyter-vuetify',
_view_module_version: '0.1.11',
_model_module_version: '0.1.11',
_theme_name: null,
primary: null,
secondary: null,
accent: null,
error: null,
info: null,
success: null,
warning: null,
anchor: null,
},
};
}

constructor(...args) {
super(...args);

if (!vuetify) {
return;
}

const themeName = this.get('_theme_name');

this.keys()
.filter(prop => !prop.startsWith('_'))
.forEach((prop) => {
vuetify.framework.theme.themes[themeName][prop] = convertColor(this.get(prop));
this.on(`change:${prop}`, () => {
vuetify.framework.theme.themes[themeName][prop] = convertColor(this.get(prop));
});
});
}
}

ThemeColorsModel.serializers = {
...WidgetModel.serializers,
};

function convertColor(colorStr) {
if (colorStr == null) {
return null;
}

if (colorStr.startsWith('colors')) {
const parts = colorStr.split('.').slice(1);
let result = colors;

parts.forEach(part => {
result = result[part];
});

return result;
}

return colorStr;
}
1 change: 1 addition & 0 deletions js/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ export { VuetifyView } from './VuetifyView';
export * from './generated';
export { HtmlModel } from './Html';
export { VuetifyTemplateModel } from './VuetifyTemplate';
export { ThemeModel, ThemeColorsModel } from './Themes';

export const { version } = require('../package.json'); // eslint-disable-line global-require
1 change: 1 addition & 0 deletions js/src/nodepsEmbed.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export { VuetifyView } from './VuetifyView';
export * from './generated';
export { HtmlModel } from './Html';
export { VuetifyTemplateModel } from './VuetifyTemplate';
export { ThemeModel, ThemeColorsModel } from './Themes';

export const { version } = require('../package.json'); // eslint-disable-line global-require
8 changes: 8 additions & 0 deletions js/src/plugins/noDepsVuetify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// import vuetify from 'vuetify';

/* The import above would break voila-vuetify and voila-embed users, so use the workaround below
* until all users have upgraded to Voila-vuetify > 0.2.2 and voila-embed > 2020-02-11, or
* ipyvuetify bumps a major version */
const vuetify = window.app && window.app.$vuetify && { framework: window.app.$vuetify };

export default vuetify;
14 changes: 10 additions & 4 deletions js/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,13 @@ module.exports = [
module: {
rules: rules
},
externals: ['@jupyter-widgets/base', 'jupyter-vue', '@mariobuikhuizen/vuetify', 'material-design-icons-iconfont', 'typeface-roboto', '@mdi/font'],
externals: ['@jupyter-widgets/base', 'jupyter-vue', '@mariobuikhuizen/vuetify/dist/vuetify.min.css', 'material-design-icons-iconfont', 'typeface-roboto', '@mdi/font', 'vuetify'],
mode: 'production',
resolve: {
alias: { './VuetifyView$': path.resolve(__dirname, 'src/nodepsVuetifyView.js') },
alias: {
'./VuetifyView$': path.resolve(__dirname, 'src/nodepsVuetifyView.js'),
'./plugins/vuetify$': path.resolve(__dirname, 'src/plugins/nodepsVuetify.js')
},
},
},{
entry: './lib/nodepsEmbed.js',
Expand All @@ -84,10 +87,13 @@ module.exports = [
module: {
rules: rules
},
externals: ['@jupyter-widgets/base', 'jupyter-vue', '@mariobuikhuizen/vuetify', 'material-design-icons-iconfont', 'typeface-roboto', '@mdi/font'],
externals: ['@jupyter-widgets/base', 'jupyter-vue', '@mariobuikhuizen/vuetify/dist/vuetify.min.css', 'material-design-icons-iconfont', 'typeface-roboto', '@mdi/font', 'vuetify'],
mode: 'production',
resolve: {
alias: { './VuetifyView$': path.resolve(__dirname, 'src/nodepsVuetifyView.js') },
alias: {
'./VuetifyView$': path.resolve(__dirname, 'src/nodepsVuetifyView.js'),
'./plugins/vuetify$': path.resolve(__dirname, 'src/plugins/nodepsVuetify.js')
},
},
},
{// Embeddable jupyter-vuetify bundle
Expand Down

0 comments on commit af6b78c

Please sign in to comment.