I'm trying to set up multiple templates in Aurelia. Currently, I have two custom templates. No matter what I do, I am only able to load the first one I add. The second returns a 404.
For reference, here's my setup
AureliaFile:
var aurelia = require('aurelia-cli');
aurelia.command('bundle', {
js: {
'wwwroot/app-bundle': {
modules: [
'resources/main-content/main-content',
'resources/side-menu/side-menu',
'resources/index',
'main',
'app',
'aurelia-framework',
'aurelia-bootstrapper',
'github:aurelia/loader-default#0.9.0',
'github:aurelia/templating-binding#0.13.0',
'github:aurelia/templating-resources#0.13.0',
'github:aurelia/history-browser#0.6.1',
'github:aurelia/templating-router#0.14.0'
],
options: {
inject:true
}
}
},
template: {
'wwwroot/app-bundle': {
pattern: '**/*.html',
options: {
inject:true
}
}
}
});
main.js:
export function configure(aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging()
.plugin('./resources/index');
aurelia.start().then(a => a.setRoot('app'))
}
my resources folder (where my two templates are) looks like:
resources
index.js
main-content
main-content.js
main-content.html
side-menu
side-menu.js
side-menu.html
and finally, my index.js is:
export function configure(aurelia) {
aurelia.globalizeResources("./side-menu/side-menu");
aurelia.globalizeResources("./main-content/main-content");
}
i have also tried changing it to:
export function configure(aurelia) {
aurelia.globalizeResources(["./side-menu/side-menu", "./main-content/main-content"]);
}
Now, my problem description
No matter which I add first in my index.js, the second is not loaded. After I run aurelia bundle, and load the site in the browser, I see:
if i switch the load order, the other template 404's. If I include only one template in the index.js, the site loads fine, albeit without my second template. Can someone please give me a pointer as to what I have missed?
Apologies for the long post, I wanted to give as much information as possible.
To add more description, in my Aurelia-built appbundle.html and appbundle.js, I see both templates, they look 100% correct as far as i can tell.
Related
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
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.
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
I use react-router-config package from here: https://www.npmjs.com/package/react-router-config for my project. I created a Routes.js file where I set my routes configurations, it looks like this:
export default [
{
...App,
routes: [
{
...IndexPage,
path: '/',
exact: true
},
{
...CategoryPage,
path: '/computers'
},
{
...CategoryPage,
path: '/home'
},
{
...NotFoundPage
}
]
}
];
as you can see I use two paths '/computers' and '/home' to load the same component CategoryPage. I wonder if it possible to pass multiple paths in one object to load the same component, something like this:
{
...CategoryPage,
path: ['/computers','/home']
}
base on the documentation https://github.com/ReactTraining/react-router/blob/v3/docs/Glossary.md#path
path type is a string but when I read this update, I guess it's support for react router version 4.4
[https://reacttraining.com/react-router/web/api/Route/path-string-string][1]
In this example
<Route path={["/users/:id", "/profile/:id"]} component={User} />
For some reason, I think the way you wrote might be the way. You could first create your ideal structure, ex.
{
components: [...CategoryPage],
path: ['/computers','/home']
}
And then use your own utility function to transform it into your final structure. This way you can make your routing structure as flexible as you want and one source of data at the same time. I found thinking this way is more scalable than bending the routing default structure.
So normally our S3 hosted Web app index.html looks like:
<div class=app></div>
That also references the JS bundle & which React renders to and that's fine. But some elements of the site are statically generated for speed & SEO and look like:
<!-- dynamically generated content -->
<div class=app></div>
<!-- statically generated content -->
<h1>Title</h1>
<p>Information, blah blah blah</p>
<p>Lots of content</p>
Conventional wisdom might suggest having the static stuff in a ReactJS component and then reactDOM.renderToString(), but I don't want to do it that way since it's rather complex to do it that way since the static component pulls from many several APIs.
So I am struggling to find documentation for what I want. I want to be able to say for certain URLs, that a full page load is necessary (window.location). Similarly, when navigating away from a static page with content, a full page load is needed or the content need to zapped back to <div class=app>.
How do I achieve this with a react router?
this is something I would go with off the top of my head. I apologize if doesn't suit your needs/purpose. I think I understand what you are going for. I might have this wrong, but I am thinking that your static pages do not have react-route on them. Literal static pages, outside the react environment.
I'd create a whitelist for these static pages.
const whitelist = ['aboutus', 'help']
then in my routes, I'd have the fallthru, check for the path.
//psuedo code
{
path: '*',
onEnter: () => {
if(whitelist.includes(path)) {
window.location = /path
}
},
component: Four0Four,
},
or you could just prepend the static pages like so:
perhaps a url like "/static?aboutus.html"
//psuedo code
{
path: 'static',
onEnter: () => {
if(whitelist.includes(path)) {
window.location = `/static/${param}`
}
},
component: Four0Four,
},
When you come back to the "react-route react" app, I wouldn't think you'd have to do anything as the react-router will pick up from the url you move back to.
You could also use the "Listener" on the location event.
browserHistory.listen(location => {
// do your checking for the static pages here
});
I hope I am not too far off base on my interpretation, if I am. Let me know and I'll delete my response.