PVR Tech Studio
Dev customizing

Customizing & Extending

Re-theme via LESS tokens, customize dark mode, add pages and locales, swap the API base, and consume the design-system in React/Vue.

4 min read
Updated June 21, 2026

You customize Taxi CRM 2026 at its source: the LESS tokens drive every edition's look, the PUG templates drive the HTML pages, and the shared design-system carries it all to React and Vue. This guide covers theming, dark mode, adding pages and locales, swapping the API base, and consuming the design-system in the Vite editions.

Theming via LESS tokens

The design tokens live in apps/html/assets/css/01-variable.less as flat LESS variables (@name: value;). Editing them is the single highest-leverage way to re-theme: style.less imports 01-variable.less along with ~70 other partials, and the design-system build extracts those same variables into tokens.json / tokens.css for the React and Vue editions.

// apps/html/assets/css/01-variable.less
@primary:      #4f46e5;   // brand / accent colour
@app-width-lhs: 16rem;    // sidebar width
@card-bg:      #ffffff;
// …

After editing tokens, rebuild so the change propagates:

npm run ds:build      # extract tokens + compile style.css for React/Vue
npm run ship:html     # recompile the static HTML edition's CSS

build.mjs pulls the flat @name: value; variables (skipping mixins and interpolated maps) into dist/tokens.json, and emits the same set as :root { --name: value; } in dist/tokens.css. So a token edited once in 01-variable.less re-themes all three editions. The full stylesheet structure, layout variables and palette classes are documented in CSS System.

Don't hand-edit the compiled dist/style.css or apps/html/assets/css/style.css — they are regenerated from LESS on every build and your edits would be lost. Change the LESS source.

Dark mode

Dark mode is driven by a data-theme attribute on the <html> element — not a body class. app.js reads the saved preference from localStorage and the header's #themeToggle button flips it:

// what app.js does — you don't write this
document.documentElement.setAttribute('data-theme', 'dark');  // or 'light'
localStorage.setItem('theme', 'dark');

To tweak dark-mode colours, scope your rules to the [data-theme="dark"] selector and reuse the kit's theme variables rather than introducing new hex colours:

[data-theme="dark"] .panel-card    { background: var(--card-bg); }
[data-theme="dark"] .my-custom-block { color: var(--text-primary); }

For any new markup, prefer the theme CSS variables (--card-bg, --panel-bg, --input-bg, --text-primary, --border-primary, …) over fixed colours so your additions follow the theme automatically. See CSS System for the variable names.

Adding a page (HTML edition)

The HTML edition is compiled from PUG templates in apps/html/pug/. The fastest approach is to copy the page closest to what you need:

  1. Copy a PUG template — e.g. pug/roleMaster.pugpug/myMaster.pug. Top-level pug/*.pug files compile to .html; partials in pug/common_pages are shared.
  2. Edit the content block only; leave the shared header, sidebar and footer partials intact.
  3. Update the page header: the title and breadcrumb in .page-header.
  4. Link it from the sidebar: app.js activates the sidebar entry whose link matches the current file, so add a menu entry pointing at myMaster.html.
  5. Wire data-i18n keys and add the matching locale file (next section).
  6. Add a page script: create assets/js/pages/<feature>/myMaster.js and include it at the bottom of the page. Build the DataTable the way the existing scripts do — see Tables and JavaScript Helpers.
  7. Add an endpoint: add the path to API_CONFIG.endpoints in app.js (and, to share it with React/Vue, to endpoints in api-contract.mjs). See Data & API Integration.
  8. Recompile: npm run ship:html renders the new PUG to dist/public/.../myMaster.html.

Adding a locale or translations

The kit ships 8 languages (en, fr, de, es, pt, zh, ja, nl). Translations live in apps/html/assets/locales/<lang>/ as JSON, auto-discovered at runtime via the locale manifest; the design-system build copies the whole locales/ tree into dist/ so React and Vue get the same files.

  • New keys: add data-i18n="myMaster.someKey" to your markup, then add the key to assets/locales/en/myMaster.json (and the other languages) and list myMaster in that locale's manifest. Full rules in Internationalization.
  • New language: add its code to the availableLocales list in the i18n module of app.js and create a matching assets/locales/<lang>/ folder, then re-run npm run ds:build.

Swapping the API base

You point any edition at your own backend in one place — see Data & API Integration for the full contract.

  • React / Vue: pass a base to the shared helper — createApi('https://api.yourcompany.com') — or keep the same-origin /api and repoint the hosting rewrite. The default base is /api in the browser and http://localhost:8080/api on localhost.
  • HTML: change API_CONFIG.baseUrl in assets/js/core/app.js.
  • Auth header: replace headers.x_pvr_tech_studio_access (api-contract.mjs) / API_CONFIG.headers (app.js) with your real header. It is sent on every call.

Consuming the design-system in React / Vue

The React and Vue editions don't re-implement styling — they import the compiled @taxi-crm/design-system outputs. In the entry file:

// apps/react/src/main.jsx  (Vue: apps/vue/src/main.js)
import '@taxi-crm/design-system/style.css';   // compiled LESS bundle
import '@taxi-crm/design-system/tokens.css';  // :root custom properties

Then use the shared API contract and the kit's Bootstrap-5 classes in your components:

import { createApi, endpoints } from '@taxi-crm/design-system/api-contract';
 
const api = createApi();
 
export default function Drivers() {
  const [drivers, setDrivers] = useState([]);
  useEffect(() => {
    api.get(endpoints.Driver.getDriver).then((res) => setDrivers(res.data || []));
  }, []);
  return (
    <div className="card">
      <div className="card-header"><h5 className="card-title mb-0">Drivers</h5></div>
      <table className="table table-hover">{/* render res.data rows */}</table>
    </div>
  );
}

Because both style.css and tokens.css originate from 01-variable.less, re-theming the LESS tokens and re-running npm run ds:build restyles the React/Vue editions too — no component changes needed. Components and widgets are plain Bootstrap 5 plus the kit's classes; see Components and Widgets.

Where to go next

Was this page helpful?