Adding new pages
You can add new page by adding a new folder in pages
For example, components/MyComp
Then create there a new file named MyComp.js with the component code.
For example,
import React, { Component } from 'react';
import ContentWrapper from '@/components/Layout/ContentWrapper';
class MyComp extends Component {
render() {
return (
<ContentWrapper>
<div className="content-heading">MyComp Title</div>
{/* view content here */}
</ContentWrapper>
);
}
}
export default MyComp;
Important: The '@' in the path is used as an alias that resolves to the root folder of the project.
Routing
Now you have added a file under pages folder, NextJs will create automatically a route using the file name. Example
http://site.com/MyComp
If you want to have a lowercase route, just rename your files. Also, when you add a folder here it will be used as part of the route. For example, the path /pages/mycomp/mycomp will be loaded with the route http://site.com/mycomp/mycomp
See how to use Link component to customize routes.
Finally, you need to add an entry to the sidebar in order to provide a link for the new page created.
To do that, add in components/Layout/Menu.js a new menu entry with the information for your menu.
Example
const Menu = [
/* heading elements */
{
// text to show
heading: 'Heading Text',
// translation key
translate: 'sidebar.heading.KEY'
},
/* menu items elements */
{
// text to show
name: 'Item Text',
// class name to show icon
icon: 'icon-class',
// route path (not used on items with submenu)
path: 'routepath',
// translation key
translate: 'sidebar.item.KEY',
// shows a Badge right next to the text
label: { value: 10, color: 'success' },
// list of submenu items
submenu: [{
... Same format as menu items
}
}
...
Vendor assets
Vendor assets can be installed using the Node Package Manager (npm). The following command shows how to install a package so it becomes part of the project
npm install package-name --save
If you don't add the --save flag, the package won't be saved as a dependecy in package.json and it will be only available in your local project.
Once the command ends, files will be available in the node_modules folder and ready to be imported into your application code.
If the package is used globally you can import files using the file pages/_app.js
To use a package locally in your new component, you can import the files directly into the code in your component file.
Note about jQuery
Although jQuery can be imported at the top of any component, plugins that uses jQuery must be imported using require in the componentDidMount class method, because all jQuery plugins must be executed at the client and they usually fails to load at the server rendering stage.
import React, { Component } from 'react';
import $ from 'jquery';
export default class Comp extends Component {
componentDidMount() {
// jQuery plugin
require('some-jquery-plugin');
// Safe to init the plugin here
// $(some-element).plugin(...);
}
...
}
Layout settings
Layout can be changed via the following classes. This classes are applied to a custom component named SettingsProvider (components/Layout/SettingsProvider.js)which acts a wrapper to catch layout changes and inject classes that modifies the layout.
| Class name |
Description |
.layout-fixed |
Makes navbars become fixed while the user can scroll only content |
.layout-boxed |
Limits the width of the main wrapper element |
.aside-collapsed |
Condenses the sidebar showing only icons |
.aside-collapsed-text |
Condenses the sidebar showing icons and Text |
.aside-toggle |
used internally for mobiles to hide the sidebar off screen |
.offsidebar-open |
used internally to display the offsidebar component (formally the right sidebar) |
Layout setting are connect to Redux store, and reducers can be found in file store/reducers/settings.reducer.js
Translation
The translation system is custom made and the source code can be located in file components/Common/Translate.js.
This module is able to load translations files (dictionaries) located under folder static/locales and display a text associated to 'key' for the current active language.
The use is pretty similar to react-i18n but without all extra features such module provides.
This means, the custom Translate module provides,
- a 't' method to get the text associated to a key and a language,
- a 'changeLanguage' method to set another languages
- a Provider to integrate with other React components and
- a Trans component as an alternative to the 't' function.
import { withTranslation, Trans } from '@/components/Common/Translate';
class Comp extends Component {
render() {
// Translate 'translate.key' using Trans component
<Trans i18nKey='translate.key'></Trans>
// or translate using t function
{this.props.t('translate.key')}
}
}
export default withTranslation(Comp)
Note that the 't' method is automatically available in components wrapped with the withTranslation HOC . At the same time, the <Provider>component is necessary in order to allow language changes to take effect in all places where a translation is required.
You can see example of this use in file pages/_app.js
Just for reference, this module exposes the following:
| Name |
Type |
Description |
| store |
Object |
Contains loaded dictionaries |
| setDict |
method |
Set a dictionary for a specific language |
| getDict |
method |
Get a dictionary for specific language |
| fetchStore |
method |
Fetch a dictionary for specific language defined in JSON format |
| translateKey |
method |
Returns the translated text for given key and interpolates values in 'params' |
| Provider |
Component |
Component provider to pass down context to child components |
| withTranslation |
HOC |
Provide 'changeLanguage' and 't' methods |
| Trans |
Component |
Translate a given key |
Why a custom made module?
The first option for translations was the i18next module but the main issue with the i18next ecosystem is that the static loader relies on 'fs' module and this is not suitable for serverless applications to be deployed to Now, which is the intention of this template.
The react-i18next and next-18next are a bit hard to implement for SSR (considering the previous limitation with the 'fs' module) and their need of an Express middlewares also doesn't allow to easily create serverless applications. According to this issue, there's not intention to bring support for Now deployments.
The decision to prioritize a serverless implementation is because it has more limitations and considerations, than when using a custom server where one have more control on server side capabilities (e.g. routes)
So in other words, the custom Translate module was made to support serverless deployment, it does pretty much the same job proving different texts in different languages but in a simple manner and can be extensible adding more features. And, at the same time, if using a custom server it can be easily replaced with a more robust Next based implementation without too much hassle following the instructions in the next-i18next readme.
Themes
All available theme are managed by REDUX to determine which of the available themes is currently active.
To inject a theme, it's used a custom component ThemesProvider (components/Layout/ThemesProvider.js) which is connected to Redux store. Reducers can be found in file store/reducers/themes.reducers.js
Default Theme
To set a default theme open you need to set it in the initialState of themeReducer in file store/reducers/themes.reducers.js like this:
const initialState = {
path: 'themes/theme-e.css'
}
Note that selected themes are automatically saved to localStorage, if you set one as default, but there's another already saved, the saved one will be used instead.
Dynamic Layouts
By default, the layout used for any page is the one displayed for the admin views, with sidebar, header, offsidebar and content.
As it's done for the user pages like login, register, etc. add a static 'Layout" property to the class or function (if using stateless component) with the layout component, like this:
import React, { Component } from 'react';
import BasePage from '@/components/Layout/BasePage';
class Login extends Component {
....
}
// Set a different layout for this page
Login.Layout = BasePage;
export default Login;
Horizontal Layout
You can enable the horizontal menu using a similar approach
import React, { Component } from 'react';
import BaseHorizontal from '@/components/Layout/BaseHorizontal';
class MyPage extends Component {
....
}
// Set a different layout for this page
MyPage.Layout = BaseHorizontal;
export default MyPage;
To set the Horizontal layout for all pages at once, edit and replace the default used in file pages/_app.js
Deploy serverless with Now
The template is ready to work as a serverless application and to deploy with Now v2.
To do that follow this steps:
Go to Now website and download the now-cli
Edit next.config.js and uncomment the target: serverless entry
Edit now.json and configure your application name and routes
Once ready, run the command "now" in the root folder of the project, if everything goes fine you will start seeing the output and when done your app will be deployed and ready online.
For more information please visit Now documentation: https://zeit.co/docs/v2/deployments/basics/
Custom server
A custom server is included in the file server.js
This file contains mainly the definition of routes that are handled via Express. This is necessary because Next automatically will take control only over generated routes from pages directory.
For example, consider the route:
<Link href="/user/login" as="/login" />
When you use a different route path, like using the "as" property in the Link component, on the client it will be handled by the browser, and Next will display "/login" in the URL bar. But, if you hit reload, on the server Next will try to find a file /pages/login which is associated with /login route (the real path is /pages/user/login) so here is where a custom server is needed to catch those "special routes" and return the right file.
A similar situation happens when you need to use route params, like is used for the "Forum" routes.
When using Now deployments, this routes are configured using now.json file.
Seed Project
This project is an application skeleton. You can use it to quickly bootstrap your ReactJS webapp projects and dev environment for these projects. The seed app doesn't do much and has most of the feature removed so you can add them as per your needs just following the full-features version as example.
This project is provided in order to start with the template using a different approach. Usually, templates will come with all features working and you need to remove them one by one in the way you don't need them.
With the seed project you can start adding custom features and others from the full project to make grow your app.
Since the files and structure is the same for the full and seed versions, you can save time using comparison tools that allows to apply changes from full features project into the seed project.