Xpulse Template Docs

Download as pdf or txt
Download as pdf or txt
You are on page 1of 17

Xpulse documentation

Getting Started
First of all, Thank you so much for purchasing this template and for being our valued customer. You are awesome! You are entitled to get
free lifetime updates to this product and 6 months support from the css ninja team directly. Xpulse is a product built by Css Ninja.

This documentation has been written to help you regarding each step of setup and customization. Please go through the documentation
carefully to understand how this template is made and how to edit this properly. HTML CSS, and Next.js / React framework knowledge is
required to customize this template.

You are currently reading the Xpulse {{ theme.version }} documentation. The product uses:

ReactJs (v18+)
NextJs (v13+) pages router
Typescript (v5+)
TailwindCss (v3+)
Fuse.js a powerful, lightweight fuzzy-search library.
Apex Charts for creation of interactive, responsive charts and graphs.
date-fns for date and time manipulation.
Class Variance Authority for creating style variants.
React Beautiful DnD for implementing drag-and-drop functionality in React applications.

What’s inside the release?


The Xpulse release contains a single project: - template: contains the full source code of the template which runs the
https://xpulse.cssninja.io/ demo

release-xpulse-{{ theme.version }}.zip


├── template-xpulse-{{ theme.version }}.zip

You can also unlock your github access to get the latest version of the template directly from github.
https://cssninja.io/faq/github-access

Prerequisites
1. A good code editor
VSCode settings are preconfigured
2. A supported web browser (Chrome, Edge, Firefox, …)
3. Node.js LTS(> 16.15.x) installed
4. Familiarity with the command line
5. Knowledge with Typescript(> 5.x) (should not be installed globally)

Install Node.js

First, check if you already have Node.js and pnpm installed. To check if you have Node.js installed, run this command in your terminal:

node -v

If Node.js is not installed on your machine, you can go to the official nodejs.org website, and choose the version depending on your
operating system:

Install Node.js on Windows, Linux or Mac OSX

You can also use Node Version Manager, or Volta.sh, to manage multiple Node.js versions on your machine.

Enable pnpm with corepack

We recommend pnpm, which can be enabled with:

corepack enable
corepack prepare pnpm@latest --activate

Corepack is a script that acts as a bridge between Node.js projects and the package managers they are intended to be used with
during development.
In practical terms, Corepack will let you use Yarn and pnpm without having to install them - just like what currently happens
with npm, which is shipped in Node.js by default.

Corepack is installed with Node.js from v16.9.x.


If your version is below, install it with: npm install -g corepack

Support
If you have any trouble while editing this template or if you simply want to ask a question about something, feel free to post your request
on our support at cssninja.io/faq/support

You can find the changelog here and inside the Xpulse source folder or you can check the changelog on the theme’s sale page.

Once again, thank you so much for purchasing this theme. As I said at the beginning, we’d be glad to help you if you have any questions
related to this theme. No guarantees, but we’ll do our best to assist and support you. If you have a more general question relating to
Xpulse, you might consider opening a ticket and ask your question in the Css Ninja support portal.

Setup your project


Starting a new project
Start by creating a new folder (e.g. my-project) and extract the template-xpulse-{{ theme.version }}.zip archive content into it.

# Create a new folder


mkdir my-project

# Extract the quickstarter archive


unzip template-xpulse-v{{ theme.version }}.zip -d my-project

# Go to the newly created folder


cd my-project

::: details Initialize a git repository We recommend to initialize a new git repository for your project and create your first commit at this
point.

# Create a new folder


git init

# Add all files to git


git add .

# Create your first commit


git commit -m "Initial commit"

:::

Remember to make your repository private if you fork or create a new git repository, as the template is a paid product.

Project overview
my-project/
├── public # Static files (images, favicon.ico, manifest.json, etc.)
├── src
│ ├── app # API routes
│ ├── components # Reusable UI components
│ ├── context # Shared state management (e.g., menu, layout, dashboard)
│ ├── data # Sample data used in components and pages
│ ├── documentation # Examples and samples used in documentation pages
│ ├── hooks # Custom hooks and reusable logic/functions
│ ├── layouts # Layout components for different sections of the site
│ ├── pages # Route components (each file represents a route)
│ ├── styles # CSS styles and font files
│ ├── types.ts # Project-wide TypeScript types/interfaces
│ └── utils # Utility functions and helpers (e.g., loading fonts, string manipulation)
├── next.config.js # Next.js configuration settings
├── package.json # Project dependencies and scripts
├── postcss.config.js # PostCSS configuration for styles
├── prettier.config.js # Prettier code formatting configuration
├── tailwind.config.js # Tailwind CSS configuration
└── tsconfig.json # TypeScript configuration settings

This is an overview of the most important files and folders in your project. Other files are for linters, testing, docker, etc.

Dependencies installation

Install the project dependencies by running the following command:

pnpm install

Start development mode

To start the development server, run one of the following commands:

pnpm dev

This will run the next dev script from the package.json file.

This should launch the development server:

The dev:vite script will start the frontend (vite) server. Vite is the build tool that we use to compile the frontend code. It replaces
webpack and vue-cli, used in earlier versions.
Read more about it on vitejs.dev

Access the Xpulse frontend in your browser at http://localhost:3000/

:::

If you have any trouble while installing, check the Common issues or contact us on our Support portal

Defining a project layout


Overview

Layouts are just components with a default slots. They are mostly used to wrap the nested routes. But they are a bit more complex than
that as they are able to receive some props to adapt to the current page. There are 6 master layouts shipped with Xpulse. In the main
demo, there is a layout switcher component that allows you to switch between them. But in your project, you will have to choose one and
stick with it, like in any application.

You have to choose a layout from the available ones.

Xpulse layouts

Layout components are located src/components/layouts

Name Identifier

Sidebar panel sidebar-panel

Sidebar panel sidebar-panel-float

Sidebar collapse sidebar-collapse


Sideblock sideblock

Sidedock sidedock

Top navigation top-navigation

The src/layouts project directory is the one that contains the active layout called inside your page. By default, it is the Default.tsx file.
However, like we said before, this file contains a lot of Demo logic with all previously mentionned layouts to be able to switch between
theme.

Notice that there is the Minimal.tsx which is basically an empty layout that you can use for specific pages, that differ from the regular ones,
like authentication, wizards etc…

You may decide to build your own layout. In that case, Minimal.tsx would be a good starting point.

Enabling your selected layout

Like we said earlier, the Default.tsx layout file should not be used for production, because it is mostly made for demo purposes. If you look
closer inside the same folder, there is a file named Default.sample.tsx, which will be the starting point for your project. You can rename it to
Default.tsx after deleting the original Default.tsx file and start from there.

Let’s take a look at this file:

import React, { FC } from 'react'


import Head from 'next/head'
import { useDashboardContext } from '@/context/DashboardContext'
import { useLayoutContext } from '@/context/LayoutContext'
import { layoutWrapperClasses, layoutNotPushedClasses, layoutPushedClasses } from '@/components/layouts/styles'
import SidebarPanelProvider from '@/components/layouts/sidebar-panel/SidebarPanelProvider'

type LayoutColors = 'default' | 'muted'

interface LayoutProps {
children: React.ReactNode;
title?: string;
color?: LayoutColors;
fullwidth?: boolean;
horizontal?: boolean;
nopush?: boolean;
}

const Layout: FC<LayoutProps> = ({ children, title, color = 'default', fullwidth = false, horizontal = false, nopush = false }) => {
const { sidebarOpened } = useDashboardContext()

const { activeLayout } = useLayoutContext()

const wrapperClass = activeLayout.toLowerCase() + '-wrapper'

return (
<>
<Head>
<title>{title ?? 'Xpulse'}</title>
<meta name="description" content="Multipurpose Next.js Admin and Webapp UI Kit" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.png" />

<link rel="apple-touch-icon" href="/apple-icon.png" />


<link rel="apple-touch-icon-precomposed" href="/apple-touch-icon-precomposed.png" />
</Head>
<div className={`min-h-screen overflow-hidden transition-all duration-300 dark:bg-muted-900 ${color === 'muted' ? 'bg-muted-50' : 'bg-
white'}`}>
{activeLayout === 'sidebar-panel' && <SidebarPanelProvider fullwidth={fullwidth ? fullwidth : false} horizontal={horizontal ? horizontal
: false} nopush={nopush ? nopush : false} />}

<div
className={`${wrapperClass} relative min-h-screen transition-all duration-300 dark:bg-muted-900 ${layoutWrapperClasses[activeLayout]}
${
sidebarOpened && !nopush ? 'is-pushed ' + layoutPushedClasses[activeLayout] : layoutNotPushedClasses[activeLayout]
} ${color === 'muted' ? 'bg-muted-50' : 'bg-white'}
${horizontal ? '!pb-0 !pe-0 !pt-0' : ''}
`}
>
<div className={`${fullwidth ? 'max-w-full' : 'mx-auto max-w-7xl'} ${horizontal ? 'flex h-full min-h-screen flex-col [&>div]:h-full
[&>div]:min-h-screen' : ''}`}>
<div className={`${horizontal ? '' : 'pb-[100px] pt-4'}`}>{children}</div>
</div>
</div>
</div>
</>
)
}

export default Layout

Looking at the file, we can see that the default selected layout is the SidebarPanelProvider which is the sidebar panel layout. You can change
it to any other layout by replacing the SidebarPanelProvider component with the one you want to use namely:

SidebarPanelProvider for the sidebar panel layout


SidebarPanelFloatProvider for the sidebar panel float layout
SidebarCollapseProvider for the sidebar collapse layout
SideblockProvider for the sideblock layout
SidedockProvider for the sidedock layout
TopNavigationProvider for the top navigation layout

In this example, we’ll assume that you’ve chosen the default layout, which is the sidebar panel layout. You don’t have anything to change
inside our Default.tsx file. Since you’ve chosen the sidebar panel layout, you don’t need the other ones anymore. You can delete all the
other folders inside the src/components/layouts folder, besides the src/components/layouts/sidebar-panel. If you were going to use the sidebar
collapse layout, you would have to delete all the other folders inside the src/components/layouts folder, besides the
src/components/layouts/sidebar-collapse folder and so on.
Follow up by updating the layout context file, located in src/context/LayoutContext.tsx. The file starts with an array containing the different
layouts:

export const LAYOUTS = [


"sidebar-panel",
"sidebar-panel-float",
"sidebar-collapse",
"sideblock",
"sidedock",
"top-navigation",
] as const;

change it to:

export const LAYOUTS = [


"sidebar-panel",
] as const;

If you were to choose the sidebar-collapse layout, you would have to change it to:

export const LAYOUTS = [


"sidebar-collapse",
] as const;

Also, in the same file, make sure that the activeLayout variable is set to the layout you’ve chosen:

const useLayout = () => {


const [activeLayout, setActiveLayout] = useState < LayoutType > 'sidebar-panel'
//...
}

Understanding layout props

All layouts share common props that you can use to customize them. Here is a list of the props that you can use:

type LayoutColors = 'default' | 'muted'

interface LayoutProps {
children: React.ReactNode;
title?: string;
color?: LayoutColors;
fullwidth?: boolean;
horizontal?: boolean;
nopush?: boolean;
}

Let’s take a look at each one of them:

children: This is the content of the page that will be wrapped by the layout.
title: This is the title of the page that will be displayed in the browser tab.
color: This is the color of the layout. It can be either default or muted. The default color is white and the muted color is a light gray.
fullwidth: This is a boolean that allows you to set the layout to full width.
horizontal: This is a boolean that allows you to set the layout to horizontal, for horizontal scrolling pages like Kanban boards for
instance.
nopush: This is a boolean that allows you to disable the push effect of the layout (only relevant for sidebar-panel and sidebar-panel-float
layouts.).

You should now have a fully functionnal layout for your project, and a basic understanding of the props that you can use to customize it.

Setup your IDE


VSCode and ES7+ React/Redux/React-Native snippets

The recommended IDE setup is VSCode with the ES7+ React/Redux/React-Native snippets extension. This extensions provides syntax
highlighting and advanced IntelliSense for template expressions, component props and even slots validation. We strongly recommend this
setup if you want to get the best possible experience with Xpulse.

React developer tools


If you are on a Chromium based browser, we recommend that you to install the React developer tools extension from any webstore:
https://react.dev/learn/react-developer-tools

Cleaning your project


In the previous section, you learned how to install Xpulse, to setup your IDE, and to enable the layout you’ve selected for your project. Like
any template project, Xpulse ships with a lot of files that you may not need. You will therefore need to clean the project before starting
your own development. Here is a list of instructions to follow to start from a clean base. In the upcoming chapters, we will cover each of
these steps in detail and review the template structure in details, so you know what you are doing when removing stuff.

my-project/
├── public # Static files (images, favicon.ico, manifest.json, etc.)
├── src
│ ├── app # API routes
│ ├── components # Reusable UI components
│ ├── context # Shared state management (e.g., menu, layout, dashboard)
│ ├── data # Sample data used in components and pages
│ ├── documentation # Examples and samples used in documentation pages
│ ├── hooks # Custom hooks and reusable logic/functions
│ ├── layouts # Layout components for different sections of the site
│ ├── pages # Route components (each file represents a route)
│ ├── styles # CSS styles and font files
│ ├── types.ts # Project-wide TypeScript types/interfaces
│ └── utils # Utility functions and helpers (e.g., loading fonts, string manipulation)

App
In version 13, Next.js introduced a new App Router built on React Server Components, which supports shared layouts, nested routing,
loading states, error handling, and more.
├── app
│ ├── api

The App Router works in a new directory named app. The app directory works alongside the pages directory to allow for incremental
adoption. This allows you to opt some routes of your application into the new behavior while keeping other routes in the pages directory
for previous behavior. Since Xpulse is a template, we don’t have any API routes in there. We only have a demo handler used by the
uploader component, in src/app/api/upload.ts. You can safely delete the src/app folder if you don’t need it.

Components
Xpulse ships with a lot of components. You will probably not need all of them, but if you do, you can simply skip this section. Before
defining what can be deleted or not, let’s review the structure of the src/components folder.

├── components
│ ├── charts
│ ├── documentation
│ ├── elements
│ ├── layouts
│ ├── pages
│ ├── vector
│ ├── video
│ ├── widgets

Charts
The src/components/charts folder contains the chart components. You can safely delete this folder if you don’t need charts in your project.
Even if you need charts, we recommend deleting its contents and bring in the charts you need one by one, so you don’t keep unused
components inside your project.

Documentation

The src/components/documentation folder contains the documentation layout components. You can safely delete this folder since the
documentation in Xpulse is solely present for demonstration purposes.

Elements
├── elements
│ ├── addons
│ ├── base
│ ├── form
│ ├── variants

The src/components/elements folder contains all basic components, that act as building blocks for the rest of the template. You will probably
need most of them, therefore we do not recommend deleting any of those until you are done with your development. If you notice some are
unused, you can safely delete them.

Addons

The src/components/elements/addons folder contains the addons components. Everything in this folder is somehow related to a plugin or an
external library, like react-video-player or react-swiper for instance. Depending on wether you are going to use these libraries or not, it’s up
to you to decide what to remove in here.

Base

The src/components/elements/base folder contains the base components. These are the most basic components, like buttons, cards, etc. You
will probably need most of them, therefore we do not recommend deleting any of those until you are done with your development.

Form

The src/components/elements/form folder contains the form components, like inputs, selects, checkboxes and radios etc… You will probably
need most of them, therefore we do not recommend deleting any of those until you are done with your development.

Variants

The src/components/elements/variants folder contains the declarative files for component variants. Some components have complex styles that
rely on conditions to be applied. To simplify the code, we’ve moved these conditions to separate files, using the Class Variance Authority
(CVA) external library. You should never delete this folder or a lot of components might break.

Layouts
├── layouts
│ ├── sidebar-collapse
│ ├── sidebar-panel-float
│ ├── sidebar-panel
│ ├── sideblock
│ ├── sidedock
│ ├── LayoutSwitcher.tsx
│ ├── SidebarIcon.tsx
│ ├── styles.ts

Xpulse features 6 master layouts to chose from. You will probably only need one of them. You can remove the layouts you don’t need by
deleting the corresponding files in the src/components/layouts folder. For instance, if you’ve selected the sidebar-panel layout you will have to
delete all other folders inside the src/components/layouts. We’ve covered this in the previous section of this documentation.

Do not delete the styles.ts file as it is required by layouts to inject some specific styles.

Pages

├── pages
│ ├── **/*.tsx

The src/components/pages folder contains the components used in specific pages. They are usually more complex and are often using multiple
basic components. Since you’ll be deleting all the demo pages to start from a clean base, you should probably delete all the files and
directories in this folder as well. It is better to reintroduce them one by one as you need them.

Vector

```bash
├── vector
│ ├── Logo.tsx
│ ├── LogoText.tsx

The src/components/vector folder contains the Xpulse Logo and LogoText components. You should never delete this folder at risk of breaking
the template. Instead replace the contents of the files with your own logo svg code or by a png image.

Widgets

```bash
├── widgets
│ ├── *.tsx

The src/components/widgets folder contains widgets used in specific pages. They are usually more complex and are often using multiple basic
components. Since you’ll be deleting all the demo pages to start from a clean base, you should probably delete all the files and directories
in this folder as well. It is better to reintroduce them one by one as you need them.

Context
├── app
│ ├── DashboardContext.tsx
│ ├── LayoutContext.tsx
│ ├── MailboxContext.tsx
│ ├── MenuContext.tsx

The src/context folder contains the shared state management. It is mostly used to control how the layout navigation behaves and how the
state is shared between key layout components. You should never delete this folder at risk of breaking layouts.

Data
├── data
│ ├── charts
│ ├── constants
│ ├── documentation
│ ├── *.tsx

The src/data folder contains the sample data used in components and pages. You can safely delete this folder if you don’t need sample data
in your project. However, make sure you don’t delete the constants folder, as it is used by the sidebar-panel and the sidebar-panel-float
layouts. If you are not using one of those two, you can safely delete the constants folder as well.

Documentation
├── documentation
│ ├── elements

The src/documentation folder contains the examples and samples used in documentation pages. You can safely delete this folder since you
won’t need to display Xpulse documentation pages in your project.

Hooks
├── hooks
│ ├── useOnClickOutside.tsx
│ ├── usePagination.tsx
│ ├── useScroll.tsx
│ ├── useSearch.tsx
│ ├── useTheme.tsx

The src/hooks folder contains the custom hooks and reusable logic/functions. The custom hooks defined in this folder, like the click outside
handler or the dark mode management, are used in the src/components folder. You should never delete this folder at risk of breaking
components.

Layouts
Xpulse features 6 master layouts to chose from. You will probably only need one of them. You can remove the layouts you don’t need by
deleting the corresponding files in the src/components/layouts folder. For instance, if you’ve selected the sidebar-panel layout you will have to
delete all other folders inside the src/components/layouts. We’ve covered this in the previous section of this documentation.

Pages
The src/pages folder contains the page components. Each file represents a route. Since you are starting from a clean base, you can safely
delete almost all the files in this folder, beside _app.tsx, _document.tsx and 404.tsx. Make sure to remove the src/pages/documentation folder as
it contains all the documentation pages. You can choose to keep or delete the src/pages/api folder depending on your usage it (Xpulse demo
search feature uses it).

You can then create a new index.tsx file to start from scratch, like the example below:

import React from 'react'


import Layout from '@/layouts/Default'

const MyNewPage = () => {


return (
<Layout title="My New Page" color="muted">
<main>
<h1>My New Page</h1>
</main>
</Layout>
)
}

export default MyNewPage

You’ve now successfully cleaned the pages folder and have a new index page to start from.

Styles
├── styles
│ ├── addons
│ │ ├── apexcharts.css
│ │ ├── base.css
│ │ ├── editor.css
│ │ ├── gridlines.css
│ │ ├── loader.css
│ │ ├── playbars.css
│ │ ├── tooltip.css
│ ├── globals.css

The src/styles folder contains additional and optional CSS styles. Those additional styles are imported into the main file, which is
globals.css. The main CSS file should never be deleted. You should simply remove the imports of the files you don’t need. Here is the
content of the globals.css file:

@import './addons/base.css';
@import './addons/loader.css';
@import './addons/apexcharts.css';
@import './addons/tooltip.css';
@import './addons/editor.css';
@import './addons/gridlines.css';
@import './addons/playbars.css';

@tailwind base;
@tailwind components;
@tailwind utilities;

base

The src/styles/addons/base.css file contains the base styles for the template body. You should never delete this file at risk of breaking some
features.

loader

The src/styles/addons/loader.css file contains the styles for the loader component. You should not remove this file or the import in the main
CSS file at the risk of breaking some components.

apexcharts

The src/styles/addons/apexcharts.css file contains dark mode styles for the apexcharts component. You can remove this file and its import in
the main CSS file if you don’t need charts in your project.

tooltip

The src/styles/addons/tooltip.css file contains the styles for the tooltip component. You can remove this file and its import in the main CSS
file if you don’t need the tooltip component in your project.

editor

The src/styles/addons/editor.css file contains the styles for the code editor component used in the documentation example. You can remove
this file and its import in the main CSS file if you won’t have the documentation pages in your project.

gridlines

The src/styles/addons/gridlines.css file contains the styles for the gridlines aesthetic effect. You can remove this file and its import in the
main CSS file if you don’t need the gridlines effect in your project.

playbars

The src/styles/addons/playbars.css file contains the styles for the audio library playbars animation. You can remove this file and its import in
the main CSS file if you don’t need the playbars effect in your project.

Utils & Types


The src/utils folder contains a few utility functions and are in charge of loading the main font. You should never delete this folder at risk of
breaking some components. Use it instead to configure your own fonts.

Public Files
my-project/
├── public # Static files

The public folder contains the static files of your project. It contains diverse assets used by the project demo, like illustrations, icons, and
images. Explore the contents of the folder and decide what you will need in your project. You can safely delete the files you don’t need.

By now, you should have a clean base to start from. In the next section, we will cover the template customization.

Customizing Xpulse
Xpulse relies on Tailwind CSS, streamlining the customization process. Here’s a guide on adapting the product to meet your specific
needs.

Understanding Tailwind CSS

Tailwind CSS is at the core of our theme/template’s styling. It simplifies styling with a utility-first approach, using pre-defined CSS classes
directly in React/JSX. Key aspects:

Utility Classes: Apply classes like bg-blue-500 to change background color to a shade of blue, py-5 to add vertical padding of 1.25rem
and more.
Customization: Tailor the framework through the tailwind.config.js file for colors, fonts, and more.
Responsive Design: Use responsive classes for adaptable layouts.
Component Styling: Apply classes to customize individual components.
Advantages: Enhance productivity, ensure consistent styling, and prototype rapidly.
Documentation: Refer to the official Tailwind CSS documentation for more details.

Tailwind Configuration

Tailoring the configuration to your preferences is possible by accessing the tailwind.config.js file located in the project directory. This file
grants you the capability to personalize elements like colors, fonts, spacing, and additional settings to align with your specific
requirements.

read more on tailwind customization

Projects Tailwind Configuration File

tailwind.config.js

const plugin = require('tailwindcss/plugin')


const colors = require('tailwindcss/colors')

/** @type {import('tailwindcss').Config} */


module.exports = {
content: ['./src/pages/**/*.{js,ts,jsx,tsx}', './src/layouts/**/*.{js,ts,jsx,tsx}', './src/components/**/*.{js,ts,jsx,tsx}',
'./src/documentation/**/*.{js,ts,jsx,tsx}'],
darkMode: 'class',

theme: {
container: {
center: true,
},
extend: {
screens: {
xs: { max: '639px' },
sm: '640px',
md: '768px',
lg: '1025px',
xl: '1280px',
xxl: '1536px',
ptablet: {
raw: '(min-width: 768px) and (max-width: 1024px) and (orientation: portrait)',
},
ltablet: {
raw: '(min-width: 768px) and (max-width: 1024px) and (orientation: landscape)',
},
},
fontFamily: {
sans: ['var(--font-inter)'],
},
colors: {
muted: {
...colors.slate,
},
primary: colors.indigo,
info: colors.sky,
success: colors.teal,
warning: colors.amber,
danger: colors.rose,
},
},

keyframes: {
indeterminate: {
'0%': { 'margin-left': '-10%' },
'100%': { 'margin-left': '100%' },
},
'circle-chart-fill': {
to: {
'stroke-dasharray': '0 100',
},
},
wave: {
'0%': {
transform: 'scale(1)',
opacity: '1',
},

'25%': {
transform: 'scale(1)',
opacity: '1',
},

'100%': {
transform: 'scale(4.5)',
opacity: '0',
},
},
fadeInUp: {
from: {
transform: 'translate3d(0, 20px, 0)',
},

to: {
transform: 'translate3d(0, 0, 0)',
opacity: 1,
},
},
fadeInLeft: {
from: {
transform: 'translate3d(20px, 0, 0)',
opacity: '0',
},
to: {
transform: 'translate3d(0, 0, 0)',
opacity: '1',
},
},
spinAround: {
from: {
transform: 'rotate(0deg)',
},
to: {
transform: 'rotate(359deg)',
},
},
},
animation: {
'spin-slow': 'spin 3s linear infinite',
'spin-fast': 'spin 0.65s linear infinite',
indeterminate: 'indeterminate 1s cubic-bezier(0.4, 0, 0.2, 1) infinite',
},
},

plugins: [
plugin(({ addComponents, addVariant }) => {
//target progress container
addVariant('progress-container', '&::-webkit-progress-bar')

//target progress bar/inner


addVariant('progress-bar', ['&::-webkit-progress-value', '&::-moz-progress-bar', '&::-ms-fill'])

addComponents({
'.slimscroll::-webkit-scrollbar': {
width: '6px',
},
'.slimscroll::-webkit-scrollbar-thumb': {
'border-radius': '.75rem',
background: 'rgba(0, 0, 0, 0.1)',
},
'.slimscroll-opaque::-webkit-scrollbar-thumb': {
background: 'rgba(0, 0, 0, 0) !important',
},
'.mask': {
'mask-size': 'contain',
'mask-repeat': 'no-repeat',
'mask-position': 'center',
},
'.mask-hex': {
'mask-image':

"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE4MiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNjQuNzg2IDE4MS40Yy05LjE5NiAwLTIwLjA2My0

},
'.mask-hexed': {
'mask-image':

"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgyIiBoZWlnaHQ9IjIwMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNLjMgNjUuNDg2YzAtOS4xOTYgNi42ODctMjAuMDY

},
'.mask-deca': {
'mask-image':

"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkyIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNOTYgMGw1OC43NzkgMTkuMDk4IDM2LjMyNyA1MHY

},
'.mask-blob': {
'mask-image':

"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTAwIDBDMjAgMCAwIDIwIDAgMTAwczIwIDEwMCA

},
'.mask-diamond': {
'mask-image':

"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTAwIDBsMTAwIDEwMC0xMDAgMTAwTDAgMTAweiI

},
})
}),
function ({ addBase, theme }) {
function extractColorVars(colorObj, colorGroup = '') {
return Object.keys(colorObj).reduce((vars, colorKey) => {
const value = colorObj[colorKey]

const newVars = typeof value === 'string' ? { [`--color${colorGroup}-${colorKey}`]: value } : extractColorVars(value, `-${colorKey}`)

return { ...vars, ...newVars }


}, {})
}

addBase({
':root': extractColorVars(theme('colors')),
})
},
],
}

This theme/template comes with built-in support for both ☀ light mode and dark mode. This functionality is achieved through the
utilization of dark variants to apply the appropriate classes for dark mode.

Configuration imports

The tailwind configuration file starts with commonjs (using require instead of import) import statements:

const colors = require('tailwindcss/colors')


const plugin = require('tailwindcss/plugin')

We are doing 2 things:

We first load the colors object from tailwind to be able to access the native colors later in the config file
We then load the plugin object to be able to use tailwind plugins later in the file.
Dark mode & Content

We then take care of configuring the Dark mode as well as the files to parse, looking for tailwind classnames tocompile in the final bundle:

module.exports = {
content: ['./src/pages/**/*.{js,ts,jsx,tsx}', './src/layouts/**/*.{js,ts,jsx,tsx}', './src/components/**/*.{js,ts,jsx,tsx}',
'./src/documentation/**/*.{js,ts,jsx,tsx}'],
darkMode: 'class',
// ...rest of config
}

We are doing 2 things:

We are first telling tailwind to use the class implementation of the dark mode. This means that when the dark mode is toggled, a .dark
class is added to the html DOM element, affecting all the application styles and colors. See Tailwind docs for more details about dark
mode.

<!--Dark mode disabled-->


<html></html>

<!--Dark mode enabled-->


<html class="dark"></html>

We then tell tailwind to look for classes to compile inside all files residing inside the project folders, including files ending with ts, tsx,
jsx and js extensions. Learn more about content parsing by taking a look at the Tailwind docs.

Extending the base theme

The tailwind configuration file provides a very convenient way of overwriting the default theme and set your own variables. Everything
related to theme customization goes inside the extend theme section of the configuration file:

module.exports = {
// ...previous config elements
theme: {
extend: {
// The theme configuration goes here.
},
},
// ...rest of config
}

There are several things we can change in there. If you want more details about the tailwind configuration, you can always read the
dedicated section of the Tailwind docs. Let’s get back to Xpulse and deep dive in each subsection of the theme configuration.

Breakpoints

In Tailwind CSS, responsive breakpoints are known as screens. Being a mobile first framework, screens are set in an ascending manner, so
you alway design mobile first. Here is the defaul Tailwind configuration:

module.exports = {
// ...previous config elements
theme: {
extend: {
screens: {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
xxl: '1536px',
},
},
},
// ...rest of config
}

While the defaults are pretty satisfying, we though that we could tweak them a little bit to get the most out of it, and to be able to face
those very particular edge cases that come up from time to time. Here is Xpulse’s screens configuration:

module.exports = {
// ...previous config elements
theme: {
extend: {
screens: {
xs: { max: '639px' },
sm: '640px',
md: '768px',
lg: '1025px',
xl: '1280px',
xxl: '1536px',
ptablet: {
raw: '(min-width: 768px) and (max-width: 1024px) and (orientation: portrait)',
},
ltablet: {
raw: '(min-width: 768px) and (max-width: 1024px) and (orientation: landscape)',
},
},
},
},
// ...rest of config
}

Let’s go through the changes we’ve made. We’ve added an xs screen that, opposed to the others that follow an ascending pattern, is
capped to 639px to face some very rare edge cases where you’d like to have something only applied on very small screens. We’ve also
decided to push the lg breakpoint to 1025px instead of 1024px to exclude landscape tablets from desktop display, simply because there is not
as much room on a landscape tablet as there is on a desktop screen, implying therefore layout adjustments between the two. And finally,
we’ve added two raw screens called ptblet (stands for portrait tablet) and ltablet (stands for landscape tablet) to handle specific layouts
rendered in both orientations at maximum design quality.

Colors

Tailwind CSS provides a very advanced and fully customizable color system. If you don’t know anything about Tailwind colors, we
recommend that you take a look at . the Tailwind docs to learn more about them. In Xpulse, we use the theme section of the configuration
file to configure our own colors, that we will be using in the template. It also means, that you can do the same thing to change all the
template colors to match your branding. Here is the color configuration of Xpulse:

module.exports = {
// ...previous config elements
theme: {
extend: {
colors: {
muted: {
...colors.slate,
},
primary: colors.indigo,
info: colors.sky,
success: colors.teal,
warning: colors.amber,
danger: colors.rose,
},
},
},
// ...rest of config
}

Tailwind CSS provides 22 prebuilt colors, each one having 10 different shades, from the lightest one to the darkest one. Let’s talk about
some of our choices. First, even if the system is pretty complete, we felt it needed an additional really darker shade to enhance dark mode
renders. Therefore we decided to add an additional shade to the gray based Tailwind colors.

Consider the slate, gray, zinc, neutral and stone colors like base grey-ish backgrounds and tints for your design system and UI elements.
Avoid at all costs mixing them as it will affect the consistency of your color system. Instead use one of those consistently throughout your
design.

Following the gold rule in the above warning, we’ve decided to abstract the gray color we want to use for the template inside the muted
variable.

muted: colors.slate,

That simply is a shortcut to use our slate color through the template without taking the risk of mixing with another tint of gray. Therefore,
instead of doing:

<span class="text-slate-600"></span>

We now simply write:

<span class="text-muted-600"></span>

Yeah, we pretty much know what you’re going to say: “Hold on, this is pretty and nice, but how is it going to help me with my
development? What benefit is this bringing?”.

First, you don’t take the risk of mixing unconsistent gray shades, having gray in some parts, slate in others, and maybe stone
somewhere else. The main gray shade is abstracted in the muted color variable and prevents any potential errors, like when multiple
people work on the same project.
Second, if you want to change the overall look of your app, you can do it anytime. You just need to switch the color linked to the muted
variable, like this:

// If you want a slate dominant in your layout


muted: colors.slate,

// If you want a gray dominant in your layout


muted: colors.gray,

// If you want a zinc dominant in your layout


muted: colors.zinc,

// If you want a neutral dominant in your layout


muted: colors.neutral,

// If you want a stone dominant in your layout


muted: colors.stone,

we use the same mecahnism to abstract other colors that you might need in a web project, like a primary color or other colors like success
and danger that symbolize some application states. You can configure those colors as shortcuts as well:

//The template primary color


primary: colors.indigo,

//The blue-ish info state


info: colors.sky,

//The green-ish success state


success: colors.teal,

//The orange-ish warning state


warning: colors.amber,

//The red-ish danger state


danger: colors.rose,

Therefore, instead of using the indigo color, we abstract it to primary:

<!--You shouldn't do that-->


<span class="text-indigo-600"></span>

<!--This is the right way-->


<span class="text-primary-600"></span>

You should now have a good understanding of how colors work in Xpulse. Take a look at how we use them inside the template to get a
more precise idea of the possibilities.

Fonts

Tailwind CSS provides a very simple way to abstract your fonts, like we did with colors. If you don’t know anything about Tailwind font
families, we recommend that you take a look at the Tailwind docs to learn more about how to configure and use them. In Xpulse, we use
the theme section of the configuration file to configure our own fonts. It also means, that you can do the same thing to change all the
template fonts to match your branding. Here is the color configuration of Xpulse:

module.exports = {
// ...previous config elements
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
},
},
// ...rest of config
}

We use the Inter font as our main font. You then call this font in your templates by using the font-sans class expression. The font source is
configured inside the src/utils/fonts.ts file. We load the Inter font from the next/font/google package:

import { Inter } from 'next/font/google'

export const inter = Inter({


variable: '--font-inter',
weight: ['200', '300', '400', '500', '700', '900'],
subsets: ['latin'],
})

Only defining your font in the tailwind.config.js file is not enough. You also need to load the font source in your application. We do it in the
src/utils/fonts.ts file, but you can do it anywhere you want, as long as it is loaded before the tailwind.config.js file.

You could also follow the same pattern if you want to customize the native font-serif and font-mono stacks that Tailwind provides by default.
You could add something like this in the configuration above:

module.exports = {
// ...previous config elements
theme: {
extend: {
fontFamily: {
serif: ['Some Font Name', 'serif'],
mono: ['Some Font Name', 'monospace'],
},
},
},
// ...rest of config
}

Keyframes

Keyframes are animation definitions written in CSS. While Tailwind provides many of these out-of-the-box, we still needed to add specific
ones for our template, using that theme configuration section of the tailwind.config.js file:

module.exports = {
// ...previous config elements
theme: {
extend: {
keyframes: {
indeterminate: {
'0%': { 'margin-left': '-10%' },
'100%': { 'margin-left': '100%' },
},
'circle-chart-fill': {
to: {
'stroke-dasharray': '0 100',
},
},
wave: {
'0%': {
transform: 'scale(1)',
opacity: '1',
},

'25%': {
transform: 'scale(1)',
opacity: '1',
},

'100%': {
transform: 'scale(4.5)',
opacity: '0',
},
},
fadeInUp: {
from: {
transform: 'translate3d(0, 20px, 0)',
},

to: {
transform: 'translate3d(0, 0, 0)',
opacity: 1,
},
},
fadeInLeft: {
from: {
transform: 'translate3d(20px, 0, 0)',
opacity: '0',
},
to: {
transform: 'translate3d(0, 0, 0)',
opacity: '1',
},
},
spinAround: {
from: {
transform: 'rotate(0deg)',
},

to: {
transform: 'rotate(359deg)',
},
},
},
},
},
// ...rest of config
}

We extend the Tailwind default keyframes by adding two of our own animations, that we will be using in some components.

animations

Like we saw in the previous section, we’ve added some new keyframes. We’re now going to use them in new animation we are also going
to add to Tailwind CSS.

module.exports = {
// ...previous config elements
theme: {
extend: {
animation: {
'spin-slow': 'spin 3s linear infinite',
'spin-fast': 'spin 0.65s linear infinite',
indeterminate: 'indeterminate 1s cubic-bezier(0.4, 0, 0.2, 1) infinite',
},
},
},
// ...rest of config
}

We are declaring the indeterminate and spin-* animation that make use of the keyframes we’ve defined earlier. We also add the animation-
timing-function and duration properties, like in traditional CSS. Once our animations are added, we can then simply use them in our Html
template by calling the animate-indeterminate or the animate-spin-* classes.

Adding plugin utilities

In Xpulse, we use the plugin object to add flat utilities directly in the config file:

module.exports = {
// ...previous config elements
theme: {
extend: {
plugins: [
plugin(({ addComponents, addVariant }) => {
//target progress container
addVariant('progress-container', '&::-webkit-progress-bar')

//target progress bar/inner


addVariant('progress-bar', ['&::-webkit-progress-value', '&::-moz-progress-bar', '&::-ms-fill'])
}),
function ({ addBase, theme }) {
function extractColorVars(colorObj, colorGroup = '') {
return Object.keys(colorObj).reduce((vars, colorKey) => {
const value = colorObj[colorKey]

const newVars = typeof value === 'string' ? { [`--color${colorGroup}-${colorKey}`]: value } : extractColorVars(value, `-


${colorKey}`)

return { ...vars, ...newVars }


}, {})
}

addBase({
':root': extractColorVars(theme('colors')),
})
},
],
},
},
// ...rest of config
}

The classes added above will are available everywhere in the project and are also compatible with the Tailwind responsive-variants that rely
on the breakpoints you’ve defined earlier.

Adding plugin components

we can also use the plugin object to add flat CSS components directly in the config file:

module.exports = {
// ...previous config elements
theme: {
extend: {
plugins: [
plugin(function ({ addComponents }) {
addComponents({
'.slimscroll::-webkit-scrollbar': {
width: '6px',
},
'.slimscroll::-webkit-scrollbar-thumb': {
'border-radius': '.75rem',
background: 'rgba(0, 0, 0, 0.1)',
},
'.slimscroll-opaque::-webkit-scrollbar-thumb': {
background: 'rgba(0, 0, 0, 0) !important',
},
'.mask': {
'mask-size': 'contain',
'mask-repeat': 'no-repeat',
'mask-position': 'center',
},
'.mask-hex': {
'mask-image':

"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE4MiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNjQuNzg2IDE4MS40Yy05LjE5NiAwLTIwLjA2My0

},
'.mask-hexed': {
'mask-image':

"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgyIiBoZWlnaHQ9IjIwMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNLjMgNjUuNDg2YzAtOS4xOTYgNi42ODctMjAuMDY

},
'.mask-deca': {
'mask-image':

"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkyIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNOTYgMGw1OC43NzkgMTkuMDk4IDM2LjMyNyA1MHY

},
'.mask-blob': {
'mask-image':

"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTAwIDBDMjAgMCAwIDIwIDAgMTAwczIwIDEwMCA

},
'.mask-diamond': {
'mask-image':

"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTAwIDBsMTAwIDEwMC0xMDAgMTAwTDAgMTAweiI

},
})
}),
],
},
},
// ...rest of config
}

The classes added above will are available everywhere in the project. They work like traditional CSS. Also, keep in mind that unlike the
plugin utility classes we’ve added earlier, these component utilities are do not generate responsive-variants.

Adding Custom Styles:

You have the flexibility to incorporate custom styles in different ways within your project.

1. Adding global styles

You can introduce custom styles by defining CSS classes in your src/styles/global.css file:

@tailwind base;
@tailwind components;
@tailwind utilities;

.btn-fav {
padding: 10px;
}

By declaring class btn-fav in global.css , you make it accessible throughout your project, and it can be utilized anywhere.

2. Adding Inline Styles to React Components

import Button from '@/components/elements/buttons/Button'

export default function Login() {


return (
<div>
<Button color="primary" variant="raised" className="!h-12 w-full mb-5 mt-2 shadow">
Login
</Button>

{/* more component logic */}


</div>
)
}

This approach allows you to conveniently pass your custom classes via the className prop, and they will be applied to components
that accept class assignments.

3. Advanced Styling Options: Tailwind Components, Utilities, and More

For more advanced customization, Tailwind CSS offers the ability to create custom styles through its components , utilities, and other
methods. These options allow you to extend Tailwind CSS to suit your project’s specific styling needs.

Component Customization

Some components offer the ability to customize their styling using props, such as the <Button/> component, which accepts both variant and
color props, in addition to its default button attributes.

The styles for the buttons, referred to as buttonStyles, are generated using Class Variance Authority to prevent conflicts between classes.
These styles can also be applied to elements like <Link> or <a> to give them the appearance of a button.

Furthermore, you can override classes in the base styles of components by prefixing them with an exclamation mark !, making the class
important.

import Button from '@/components/elements/buttons/Button'


import { buttonStyles } from '@/components/elements/colors/btn-colors'

const Invoice = () => {


return (
<div>
{/* Button with primary color and raised appearance */}
<Button color="primary" variant="solid" className="mx-1 !min-w-[auto] flex-grow-[2]">
Edit
</Button>

{/* classes will be appended to the Default styling */}


<Button className="mx-1 !min-w-[auto] flex-grow-[2]">Share</Button>

{/* Default styling for the button */}


<Link
href="/content-invoice"
className={buttonStyles({
className: 'h-9 min-w-[56px] !rounded-r-none px-4 py-2 text-center',
})}
>
View
</Link>
</div>
)
}

If you are using Visual Studio Code (VSCode) you can hit Ctrl + Space to see all the available props of a component

Conditional Styling

Implementing conditional styling based on dynamic data or user interactions can be achieved as below.

1. Utilizing a string literal for conditional styling based on state or props:

const IconButton: FC<{


shape?: 'square' | 'round',
}> = ({ shape = 'square', className: classes }) => {
return <button className={` ${shape === 'square' ? 'rounded-xl ' : 'rounded-full'} h-[44px] w-[44px] min-w-[44px] ${classes}`}></button>
}

In this approach, the class rounded-xl is applied when shape equals “square,” otherwise, rounded-full is applied.

2. Leveraging Tailwind CSS variants or modifiers

import Button from '@/components/elements/buttons/Button'

const Component = () => <Button className="dark:hover:border-muted-800">Edit</Button>

the class dark:hover:border-muted-800 is applied when the element is hovered in dark mode.

You should know understand how to customize the template to match your branding. Let’s now take a look at how to deploy the template.

Deploying Xpulse
This guide will show you basic steps to build and deploy your Xpulse app. As Xpulse use Next.js, we recommend to read the Next.js
Deployment Guilde to learn more.

Default build
Once you are done with the development, you can build your app for production with the following command:

pnpm build

This command builds the app for production to the .next folder. It correctly bundles React in production mode and optimizes the build for
the best performance. The output is a Node.js server that serve your pages and API routes. You can preview it with the following
command:

pnpm start

This way is recommended if you want to deploy your app to a serverless platform like Vercel where you can link your repository and deploy
your app in a few clicks.

Self-hosting
Standalone build

If you want to self-host your app, Next.js can generate a standalone build that contains only needed dependencies, so you can deploy it to
any hosting platform that supports Node.js or create a Docker image.

To generate a standalone build, you can directly run a build with:

NEXT_OUTPUT=standalone pnpm build

This automaticaly set the following configuration to your next.config.mjs file:

const nextConfig = async (phase, { defaultConfig }) => {


return {
output: 'standalone',
}
}

export default nextConfig

This will create a .next/standalone folder that contains a standalone build of your app that you can run using node .next/standalone/server.js.

You can deploy this server to any hosting platform that supports Node.js

The standalone build does not include the ./public folder neither the generated static assets, you need to use a CDN or copy them in
.next/standalone/. See the Dockerfile example below.

::: details Expand to see Dockerfile using the standalone build

# Build stage
FROM bitnami/node:18 AS build
WORKDIR /app

RUN corepack enable && corepack prepare pnpm@latest --activate

COPY package.json ./
COPY pnpm-lock.yaml ./
RUN pnpm install

COPY . .
RUN NEXT_OUTPUT=standalone pnpm build

# Runtime stage
FROM bitnami/node:18 AS prod
WORKDIR /app

RUN corepack enable && corepack prepare pnpm@latest --activate

RUN groupadd --gid 10001 xpulse


RUN useradd --create-home --uid 10001 --gid xpulse xpulse
RUN chown --recursive xpulse:xpulse /app

# Copy public files


COPY --from=build --chown=xpulse:xpulse /app/public ./public
# Copy standalone build
COPY --from=build --chown=xpulse:xpulse /app/.next/standalone ./
# Copy static files
COPY --from=build --chown=xpulse:xpulse /app/.next/static ./.next/static

USER xpulse

EXPOSE 3000

ENV PORT 3000


ENV HOSTNAME localhost

CMD ["node", "server.js"]

You can then build and run your Docker image:

docker build --tag my-xpulse-app:1.0.0 .


docker run --rm --publish 3000:3000 my-xpulse-app:1.0.0

Static export

If you want to deploy your app to a static hosting platform, a CDN or a serverless platform that does not support Node.js, you can generate
a static export of your app.

To generate a static build, you can directly run a build with:

NEXT_OUTPUT=export pnpm build

This automaticaly set the following configuration to your next.config.mjs file:

const nextConfig = async (phase, { defaultConfig }) => {


return {
output: 'export',
images: {
unoptimized: true,
}
}
}

export default nextConfig

This will create a out folder that contains a static export of your app that you can deploy to any static hosting platform, you can preview it
with the following command:

npx serve ./out

::: details Expand to see Dockerfile using the export build and Nginx

# Build stage
FROM bitnami/node:18 AS build
WORKDIR /app

RUN corepack enable && corepack prepare pnpm@latest --activate

COPY package.json ./
COPY pnpm-lock.yaml ./
RUN pnpm install

COPY . .
RUN NEXT_OUTPUT=export pnpm build

# Runtime stage
FROM bitnami/nginx:1.24 AS prod
WORKDIR /app

# Copy export build


COPY --from=build /app/out ./

You can then build and run your Docker image:

docker build --tag my-xpulse-app:1.0.0 .


docker run --rm --publish 8080:8080 my-xpulse-app:1.0.0

:::

Useful links
Deploying Guide on nextjs.org
Rendering Strategies on nextjs.org
Edge and Node.js on nextjs.org
Configuration Reference on nextjs.org

Customer support
Please remember you have purchased a very affordable theme and you did not pay for a full-time web design agency. We will help with
your issues, but these requests will be put on a relevant priority, regarding their nature. Support is provided for your comfort and for a
best possible experience, so please be patient, polite and respectful, as we are towards you.

Support includes
Responding to questions or problems regarding the item and its features
Fixing bugs and reported issues
Providing updates

Support does not include


Customization and installation services
Support for third party software and plug-ins

Before Support
Check if your issue is not already resolved on Common issues
Make sure your question is a valid Theme Issue and not a customization request
Make sure you have read through the documentation and any ressources before asking support on how to accomplish a task
Make sure to double check the theme FAQs.
If you have customized your theme and now have an issue, back-track to make sure you didn’t make a mistake. If you have made
changes and can’t find the issue, please provide us with your changelog.
Almost 80% of the time we find that the solution to people’s issues can be solved with a simple “Google Search”. You might want to
try that before seeking support. You might be able to fix the issue yourself much quicker than we can respond to your request.
Make sure to state the name of the theme you are having issues with when requesting support.

You might also like