Support multiple themes under single build in ExtJs - extjs

I have to change the theme based on some event. What i understood from sencha docs and kitchen sink is we have to make entries of all the themes under "builds" block of app.json
"builds": {
"classic": {
"toolkit": "classic",
"theme": "theme-classic"
},
"triton": {
"toolkit": "classic",
"theme": "theme-triton"
}
},
Post build, we can reload application as below to get specific theme.
location.search = "/?profile=classic";
location.search = "/?profile=triton";
But its not working as expected. Any hints please.

You are only halfway there. Sencha Cmd will generate different manifests for your themes. Now you now have to chose the corresponding manifest upon application load. Take a look at Dynamic Manifest section from Microloader's docs.
There are times when you may want to select a build profile
client-side. To simplify this, the Microloader defines a hook method
called “Ext.beforeLoad”. If you define this method like the following,
you can control the name or content of “Ext.manifest” prior to the
Microloader processing it while leveraging its platform detection.
For your case it would look something like this:
<script type="text/javascript">
var Ext = Ext || {};
Ext.beforeLoad = function (tags) {
var theme = location.href.match(/profile=([\w-]+)/);
theme = (theme && theme[1]) || 'classic';
Ext.manifest = theme;
};
</script>

Related

Docusaurus 2 How to add custom react component in navbar

From the docusaurus docs, the navbar items can only have certain types like link, dropdown and search.
How do I add custom buttons like if I want to add login button ?
This would really depend on the type of functionality you're wanting to see out of the item you add to the navbar, but the development patterns should be similar across various implementations.
If you're trying to trigger something like a login modal when the user clicks your custom button, you could specify the following in docusaurus.config.js:
module.exports = {
themeConfig: {
navbar: {
items: [
{
href: '#login',
label: 'Login'
}
]
}
},
scripts: [
'https://yourdomain.com/customscript.js'
]
};
Then in a script, customscript.js, you could include the following:
document.querySelector('[href="#login"]')
.addEventListener('click', () => {
console.log('Login button clicked.');
});
Docusaurus requires that either href or to is given on each navbar item, so that's why I chose the weird selector, but if you wished, you could also specify className on the item, and then use that as a selector too. If you want the item to be something other than a link, you could set the outerHTML in your custom script or use replaceWith().
Keep in-mind that depending on the way your site's routing is configured, you may need to re-apply the logic in your custom script if the link node is re-written to the DOM by React.
As far as I know, there isn't really a perfect way to accomplish this at the moment, but v2 is also still in development, so the plugin exposures are getting better with each release.
The temporary workaround works well
https://github.com/facebook/docusaurus/issues/7227

Dynamically changing Less variables in React Gatsby app with Ant Design at runtime

We are building a White Label platform using React, GatsbyJs and Ant Design. We are stuck with Gatsby and Ant Design because we are migrating from an existing system and changing any of those would bring huge impact. Also, we must have a single deploy. Having a build for each White Label is not an option.
So, we need to be able to change style (mainly color) at runtime.
The problem is: Ant Design uses less variables to define it's themes and we're not able to change them at runtime, not even with less's modifyVars.
The thing is we MUST change less variables, and not global CSS or use other means
Ant Design derivates the main variables many times to get adjacent properties. So, for instance, if we define #primary-color as red, when we add a Button to the screen, Ant Design also defines it's border color, hover color, and many other details with different shades of red.
This means that, if we were to use other styling tool, we would need to generate those color derivations and replace every little property for every component. This would be chaos.
Scenario
We are using gatsby-plugin-antd and gatsby-plugin-less to load less and change vars at build time. Our gatsby-config.js looks like this:
module.exports = {
siteMetadata: {
siteUrl: 'https://www.yourdomain.tld',
title: 'yourtitle'
},
plugins: [
'gatsby-plugin-root-import',
'gatsby-plugin-typescript',
{
resolve: 'gatsby-plugin-antd',
options: {
style: true
}
},
{
resolve: 'gatsby-plugin-less',
options: {
lessOptions: {
javascriptEnabled: true,
modifyVars: {
'primary-color': '#FFFFFF',
'link-color': '#000000',
'success-color': '#FFFFFF',
'warning-color': '#000000'
}
}
}
}
]
};
We import styling in our gatsby-browser.js file:
import './src/styles/index';
Our styles/index has:
import 'tachyons';
import './global.css';
import './antd.less';
antd.less:
#import '~antd/dist/antd.less';
And global.css has some general CSS for the project.
It's working fine with the defined variables at build time.
What we attempted so far...
We have tried out this plugin:
https://github.com/mzohaibqc/antd-theme-webpack-plugin
Which supposedly does exactly what we need. But there's no example using Gatsby.
We then tried to add the plugin using the gatsby-node.js as mentioned here:
https://www.gatsbyjs.com/docs/how-to/custom-configuration/add-custom-webpack-config/
First, we tried using index.html as the indexFileName for the pluggin. It just doesn't work.
Then, following the plugin docs, we tried using indexFileName as false and importing the following scripts using Helmet at our pages/index.tsx:
<script> window.less = { async: false, env: 'production' };
</script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script> ```
Also didn't work. If we define indexFileName as false, we get memory over the heap.
If we keep indexFileName as 'index.html' and just add the scripts, we are able to call window.less.modifyVars and it returns successfully (we are logging the Promise's then and error) but it doesn't affect antd's variables.
We then tried doing something similar, but instead of loading less externally, we installed it as a node_module and imported it to the file and used it directly in a similar fashion. Got the same result: modifyVars runs and returns successfully but doesn't affect antd.
Then, we tried something a bit different: we removed gatsby plugins and tried importing less from antd directly, as suggested here:
https://ant.design/docs/react/customize-theme
So we imported it like this:
#import '~antd/lib/style/themes/default.less';
#import '~antd/dist/antd.less';
#import 'your-theme-file.less';
Also, no good. It's different from the previous scenario, because style gets updated after you save your code. No need to stop Gatsby, as the first solutions. But, modifyVars still has no affect on antd components.
Then, to isolate the issue, we tried to style a basic HTML component - a button - to check if the issue was with gatsby or antd. And... still no success. less.modifyVars didn't work to change a basic button style on runtime.
So, we think it's probably something between Gatsby and Less. We checked gatsby-plugin-antd and gatsby-plugin-less to see if we could find something, but found nothing useful.
We assume that the "less instance" or "less context" used by gatsby's less-loader during build time is not the same we are calling modifyVars on. So it doesn't affect the original vars.
Totally stuck. Please, help!
EDIT - SOLUTION
Ant Design team has just released - TODAY - a new alpha version that includes dynamic theming, using CSS Variables.
https://ant.design/docs/react/customize-theme-variable
It works fine, so far. Closing the issue.
EDIT 2
There's a more detailed solution on the accepted answer.
Ant Design team has just released - TODAY - a new alpha version that includes dynamic theming, using CSS Variables.
https://ant.design/docs/react/customize-theme-variable
It works fine, so far.
EDIT - Detailed solution
I removed gatsby-plugin-antd and gatsby-plugin-less from the project. Also removed the import of antd less file.
Instead, in my styles/index.tsx (which is imported in gatsby-browser.js), I'm importing the variables.min.css file:
import 'antd/dist/antd.variable.min.css';
Then, whenever I want to change Ant Design variables, I just use:
import { ConfigProvider } from 'antd';
...
ConfigProvider.config({
theme: {
primaryColor: '#[DESIRED_COLOR_HEX]'
}
});
Provider
Since this has to be done every time the site is loaded, I'm creating a ThemeProvider that wraps every page and defines the theme. It fetches theme data from the backend and sets Ant Design theme variables.
Example code:
import { Spin } from 'antd';
import React, { useEffect, useState } from 'react';
import { ConfigProvider } from 'antd';
import { Theme } from './theme.interface';
interface Props {
children: React.ReactNode;
}
export const ThemeProvider = ({ children }: Props): JSX.Element => {
const [themeVars, setThemeVars] = useState<Theme>(null);
useEffect(() => {
async function fetchMyAPI() {
const result = await getThemeFromBackend(); // Make API call with Axios
if (result) setThemeVars(result);
}
fetchMyAPI();
}, []);
useEffect(() => {
if (themeVars) {
ConfigProvider.config({
theme: {
primaryColor: `#${themeVars.primaryColor}`
}
});
}
}, [themeVars]);
return <div>{!themeVars ? <Spin size="large" /> : <>{children}</>}</div>;
};
And it can be used like this:
...
<ThemeProvider>
<h1>My page header</h1>
<p>Page content...</p>
</ThemeProvider>
...
Note: You can save theme data on local storage for performance improvement, so you don't have to call your backend everytime your site reloads. Maybe you'll just have to refresh it from time to time.

SortableJS not working with Onsen UI on desktop

Just copy-pasted the example code from Sortable's docs.
It works fine on any touchsreen device, but as soon as I view it on Chrome or any other desktop browser it stops working. No error, you just can't drag anymore.
Onsen UI's JS probably overwrites the drag events or something like that but couldn't manage to find the solution.
Per the answer given here: https://github.com/SortableJS/Vue.Draggable/issues/508#issuecomment-488314106
If anybody faces this issue then the following is a workaround for this;
document.body._gestureDetector.dispose()
If you need to enable it again for any reason, use the following
document.body._gestureDetector = new ons.GestureDetector(document.body);
Since my code is using Sortable in a Vue component, I ended up doing this as part of the options to Sortable.create. It seems to work well enough:
onChoose: function(event) {
if(this.$ons) {
document?.body?._gestureDetector?.dispose();
}
},
onStart: function(event) {
if(this.$ons) {
document?.body?._gestureDetector?.dispose();
}
},
onEnd: (event) => {
if(this.$ons) {
document.body._gestureDetector = new this.$ons.GestureDetector(document.body);
}
},

How to call and use embedded assets from Contentful Rich Text fields using Gatsby?

I am using Gatsby as the starter for my react app. To handle content I am using Contentful.
In my Contentful Content Model, I've created the following content types:
Short Text
Short Text
Media
Rich Text
Rich Text
Using Gatsby's gatsby-source-contenful and #contentful/gatsby-transformer-contentful-richtext plugins, I've successfully rendered my all of these content types, except in my Rich Text types I'm not able to render the Embedded Assets within it.
I've tried installing #contentful/rich-text-types via npm and using the constants MARK and INLINES based on the example in Gatsby's documentation found here
const { MARKS, INLINES } = require('#contentful/rich-text-types')
{
resolve: `#contentful/gatsby-transformer-contentful-richtext`,
options: {
renderOptions: {
/*
* Defines custom html string for each node type like heading, embedded entries etc..
*/
renderNode: {
// Example
[INLINES.ASSET_HYPERLINK]: node => {
return `<img class='custom-asset' src="${
node.data.target.fields.file['en-US'].url
}"/>`
},
[INLINES.EMBEDDED_ENTRY]: node => {
return `<div class='custom-entry' />${
node.data.target.fields.name['en-US']
}</div>`
},
},
/*
* Defines custom html string for each mark type like bold, italic etc..
*/
renderMark: {
// Example
[MARKS.BOLD]: text => `<strong>${text}<strong>`,
},
},
},
},
Ideally, I'd like for Gatbsy to automatically render image assets within the Rich Text types as <img src="[ASSET URL]" alt="[ASSET DESCRIPTION]">
Try this:
const { BLOCKS } = require('#contentful/rich-text-types')
...
renderNode: {
[BLOCKS.EMBEDDED_ASSET]: node => {
// console.log(node)
let { description, title, file } = node.data.target.fields
// console.log(file["en-US"].url)
return <img src={file["en-US"].url} />
},
},
This seems to work for me, although the image seems to be full-size, and load rather slowly. Needs additional work, but this does seem to work (at least in development)
EDIT:
It seems like the fields property on my node.data.target stopped appearing when I send my graphql query... and this stopped working... super bizarre
EDIT 2:
if you delete the .cache folder (project-root/.cache), the above issue gets fixed. https://github.com/gatsbyjs/gatsby/issues/10592

Create Dynamic theme with antd and reactjs

i am creating a web application using reactjs and antd. Now i want to add a feature in which user will select color and all the primary color or web application will be changed. I did searched on google but most of the people says that its not possible using antd . Just wondering if someone has tried before or is it doable ?
Antd supports setting a custom theme. You should use that to generate a theme based on what color the user chooses.
Example theme.js:
module.exports = () => {
return {
'primary-color': '#1DA57A',
'link-color': '#1DA57A',
'border-radius-base': '2px',
};
};

Resources