Is it possible, in sourecode, to create a complete theme palette based on a primary color like the theme builder does? - office-ui-fabric

Since the title attempts to address every part of my question, which is very difficult, I need to clearify a bit:
I want to be able to apply a theme to my Office UI Fabric application with all the different color shades an Office UI Fabric theme should have, without having to define each shade myself. The only things I want to define are the primary theme color, the body text color and the body background color. This is just what the theme generator on the Office UI Fabric website does.
So to get to the point: Is it possible to use the functionality of the theme generator in any Office UI Fabric application?
My naive approach was to use createTheme, since it accepts a partial theme, and I hoped to get a full one back:
const theme = createTheme({
palette: { themePrimary: '#007610' },
semanticColors: { bodyBackground: '#ffffff', bodyText: '#000000' },
});
loadTheme(theme);
Alas, this wasn't the case. Only the properties provided are applied.
So is there a simple (official) way to do this or are the sources of the theme creator available somewhere?

So after some investigation of the ColorPage.tsx from the Office UI Fabric repository I found the missing pieces to achieve this myself. The code below is just a very simple usage of that mechanism, that suffices my needs. For now, I don't want the user to change the main background or foreground colors, hence the simplifications. Use and extend it at your own risk, but feel free to ask me, if something isn't clear. But I guess its rather clear what's going on here.
import { loadTheme } from '#uifabric/styling';
import {
IThemeRules,
ThemeGenerator,
themeRulesStandardCreator,
} from 'office-ui-fabric-react/lib/ThemeGenerator';
import { getColorFromString } from 'office-ui-fabric-react/lib/utilities/color/getColorFromString';
import { IColor } from 'office-ui-fabric-react/lib/utilities/color/interfaces';
export default class ThemeProvider {
private themeRules: IThemeRules;
constructor() {
const themeRules = themeRulesStandardCreator();
ThemeGenerator.insureSlots(this.themeRules, false);
ThemeGenerator.setSlot(themeRules.backgroundColor, getColorFromString('#ffffff'), false, true, true);
ThemeGenerator.setSlot(themeRules.foregroundColor, getColorFromString('#000000'), false, true, true);
this.themeRules = themeRules;
}
public loadThemeForColor(hexColor: string): void {
const newColor: IColor = getColorFromString(hexColor);
const themeRules = this.themeRules;
ThemeGenerator.setSlot(themeRules.primaryColor, newColor.str, false, true, true);
this.themeRules = themeRules;
const theme = ThemeGenerator.getThemeAsJson(this.themeRules);
loadTheme({
...{ palette: theme },
isInverted: false,
});
}
}
For more insights have a look at the ColorPage.tsx yourself within the official repo, since I didn't strive to understand everything going on in there.

Related

Docusaurus: How can I have multiple versions of different docs in the docs directory?

I'm working with Docusaurus to create a documentation site for 3 different education courses - all within the docs folder.
So I'm looking for a way to have the version be different across folders in there, or figure out what the best strategy for this is.
Right now, in my docusaurus.config.js I have:
module.exports = {
presets: [
'#docusaurus/preset-classic',
docs: {
lastVersion: 'current',
versions: {
current: {
label: '1.0.0',
path: '1.0.0',
},
},
},
],
};
But I'm not sure how to keep track of 3 different versions across 3 different docs all within the same site.
Swizzle the navbar via wrapping
yarn run swizzle #docusaurus/theme-classic NavbarItem/DocsVersionDropdownNavbarItem -- --wrap
Modify the swizzled component like so:
src/theme/NavbarItem/DocsVersionDropdownNavbarItem.js:
import React from "react";
import DocsVersionDropdownNavbarItem from '#theme-original/NavbarItem/DocsVersionDropdownNavbarItem';
import { useLocation } from '#docusaurus/router';
export default function DocsVersionDropdownNavbarItemWrapper(props) {
const { docsPluginId, className, type } = props
const { pathname } = useLocation()
/* (Custom) check if docsPluginId contains pathname
Given that the docsPluginId is 'charge-controller' and the routeBasePath is 'charge-controller', we can check against the current URI (pathname).
If the pathname contains the docsPluginId, we want to show the version dropdown. Otherwise, we don't want to show it.
This gives us one, global, context-aware version dropdown that works with multi-instance setups.
You want to declare a version dropdown for each plugin in your navbarItems config property for this to work well.
const doesPathnameContainDocsPluginId = pathname.includes(docsPluginId)
if (!doesPathnameContainDocsPluginId) {
return null
}
return <DocsVersionDropdownNavbarItem {...props} />;
}
For this to work, you need to have your documentation (based on products) split up using multi-instances: (https://docusaurus.io/docs/docs-multi-instance#docs-navbar-items)
Note that the preset docsPlugin ID always is "default".
You can try to use
import {
useActivePluginAndVersion,
} from '#docusaurus/plugin-content-docs/client';
const version = activePluginAndVersion.activeVersion.name; // use label instead of name if issues arise.
instead to get the current docsPluginId, name or label.
This would be the more "robust" solution I think. That said, we do use the solution I provided above as-is and it works fine for now.

Spartacus Configurable Product Integration: Custom Normalizer nested data being overridden

I am trying to implement a custom normalizer to the configurable product feature module. I have to include a custom field in the Attributes datatype. Currently only the OccConfigurationVariantNormalizer is available, which is quite high level form a data's point of view.
My problem occurs with the execution order of the normalizers. The default normalizer ist this: https://github.com/SAP/spartacus/blob/develop/feature-libs/product-configurator/rulebased/occ/variant/converters/occ-configurator-variant-normalizer.ts which is being called after my custom normalizer. Hence, the convertGroup() function is overriding my custom attribute field.
Here is my implementation:
#Injectable({
providedIn: 'root'
})
export class CustomConfiguratorNormalizerService extends OccConfiguratorVariantNormalizer{
convertAttribute(sourceAttribute: CustomOccAttribute, attributeList: CustomAttribute[]): void{
super.convertAttribute(sourceAttribute, attributeList);
attributeList[attributeList.length - 1].customField = sourceAttribute.customField;
}
}
Extending the original Normalizer seemed like the most promising solution for the time being, and is working quite like intended. So the customField ist being present at this point in time of execution.
Afterwards the OccConfiguratorVariantNormalizer kicks in, which is defining a new Attribute array in convertGroup(), erasing my custom attribute:
convertGroup([...]) {
const attributes: Configurator.Attribute[] = [];
if (source.attributes) {
source.attributes.forEach((sourceAttribute) =>
this.convertAttribute(sourceAttribute, attributes)
);
}
[...]
};
convertAttribute(
sourceAttribute: OccConfigurator.Attribute,
attributeList: Configurator.Attribute[]
): void {
const attribute: Configurator.Attribute = {
name: sourceAttribute.name,
label: sourceAttribute.langDepName,
required: sourceAttribute.required,
uiType: this.convertAttributeType(sourceAttribute.type),
values: [],
groupId: this.getGroupId(sourceAttribute.key, sourceAttribute.name),
userInput: sourceAttribute.formattedValue,
maxlength:
sourceAttribute.maxlength + (sourceAttribute.negativeAllowed ? 1 : 0),
numDecimalPlaces: sourceAttribute.numberScale,
negativeAllowed: sourceAttribute.negativeAllowed,
numTotalLength: sourceAttribute.typeLength,
selectedSingleValue: null,
images: [],
hasConflicts: sourceAttribute?.conflicts?.length > 0 ? true : false,
};
[...]
};
If my custom normalizer was the only one I could imagine it would work, which is why I tried to inject it like this:
{
provide: VARIANT_CONFIGURATOR_NORMALIZER,
useClass: CustomConfiguratorNormalizerService,
multi: false,
}
Throwing me Error: Multi-providers mixed with single providers.
Also, using the documentation from https://sap.github.io/spartacus-docs/connecting-to-other-systems/ I cannot get it to work without extending the original Normalizer, since target will always be undefined, which probably would not be the case if my custom normalizer came in second.
I feel like this https://github.com/SAP/spartacus/issues/9046 could be related.
Any help very much appreciated :)
I was able to solve this myself. Following the reference structure for spartacus applications at https://sap.github.io/spartacus-docs/reference-app-structure/ the problem disappeared.
My best guess is that it has to do with the import order of the modules. In my current working version I import the FeaturesModule last, which seems to solve the problem.

Add CoreUI icon to DevExtreme dxDataGrid column header in Vue.js

Currently I am working on a new UI for a legacy API. Unfortunately, this one delivers HTML source code for a column header. This code usually creates a FontAwesome icon. This library will not be used in the new project.
I found a very similar icon in the Icon Library of CoreUI. Now it is only a matter of rendering the icon at this point. However, no approach has been successful so far. How can I replace the icon in the headerCellTemplate method?
Or maybe there is a completely different, much better approach to do this. I don't know if I am on the right track with this method approach. You can probably use static templates, but I don't know how to do that.
import { CIcon } from '#coreui/vue';
import { cilCheckCircle } from '#coreui/icons';
headerCellTemplate: (element, info) => {
element.innerHTML = curr.ColumnTitle;
if (element.firstChild.nodeName === 'I') {
// WORKS
//element.firstChild.innerHTML = 'Done';
// ANOTHER EXPERIMENT
//const componentClass = Vue.extend(cilCheckCircle);
//const instance = new componentClass();
//instance.$mount();
//element.removeChild(element.firstChild);
//element.appendChild(instance.$el);
// ALSO NOT WORKING
return CIcon.render.call(this, cilCheckCircle);
}
}
I finally found a solution after revisiting this interesting article.
import Vue from 'vue';
import { CIcon } from '#coreui/vue';
import { cilCheckCircle } from '#coreui/icons';
headerCellTemplate: (element, info) => {
element.innerHTML = curr.ColumnTitle;
if (element.firstChild.nodeName === 'I') {
const cIconClass = Vue.extend(CIcon);
const instance = new cIconClass({
propsData: { content: cilCheckCircle }
});
instance.$mount(element.firstChild);
}
}
I don't know, though, if this is the ideal solution. So feel free to tell me, if you have a better, less complex solution.

Can't get full screen buttons to work with highcharts-vue

I'm using the highcharts-vue wrapper within my vue project. Things are going smooth except for the fact that I can't get the viewFullscreen option to work.
I've set things up following the docs and included the following within my main.js
import exportingInit from 'highcharts/modules/exporting'`
exportingInit(Highcharts);
The export function is working within my charts. For every chart I've set up the options as follow:
exporting: {
buttons: {
contextButton: {
menuItems: ['viewFullScreen', 'downloadPNG', 'downloadJPEG', 'downloadPDF']
}
}
}
alle the buttons ar visible and working except for the viewFullscreen button. that one isn't showing.
Following the docs from the highcharts api there isn't anything mentioned about having to include extra options or so to make use of the vieFullscreen mode.
Any thoughts on this?
You need to change the first string from viewFullScreen to viewFullscreen:
exporting: {
buttons: {
contextButton: {
menuItems: ['viewFullscreen', 'downloadPNG', 'downloadJPEG', 'downloadPDF']
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/ekr2mw7f/
API Reference: https://api.highcharts.com/highcharts/exporting.buttons.contextButton.menuItems

Javascript Style Sheet in Titanium mobile

I'm a learning mobile development using Titanium Mobile framework.
I am facing a problem related to application of javascript style sheet.
When I name my jss file same as the js file, to which the style is to be applied, it works fine. But if I name it something else, it don't work. Can anybody tell me a solution. Following is my code sample.
// app.js
var win = Titanium.UI.createWindow({ backgroundColor : '#fff' });
win.add( Ti.UI.createButton({ title : 'Button A' }) );
win.open();
// app.jss, works fine
button { backgroundImage: 'grdadient_img.png'; }
// button_style.jss, don't work
button { backgroundImage: 'grdadient_img.png'; }
I never had much success using more than one JSS file. And if you follow Nandu's links you'll see that it's not really documented very well, likely to be removed from Titanium at some point. I expect that Titanium's Alloy will kill off JSS too.
If you don't want to use JSS (or Alloy yet), there is a neat way to centralise your styles using commonJS modules and optionally underscore.js e.g.
theme.js
var theme = {
tableLabel : {
color : '#3285C7',
backgroundColor : 'transparent',
inactiveColor : '#AAAAAA'
}
}
module.exports = theme;
to use
var theme = require('ui/common/Theme');
...
var myLabel = Ti.UI.createLabel(_.extend({}, theme.tableLabel, {
top : 5,
height : Ti.UI.SIZE,
width : Ti.UI.FILL,
text : "Hello world",
}));
I use _extend to take the settings from the theme and add instance specific settings like size, position etc. Don't forget the first empty object literal in the call to `_.extend()
See http://underscorejs.org/#extend
Ammar, please refer the following links. Hope it will help you
1.How to use jss correctly
2.How Does .jss feature really works in Titanium mobile SDK