diff --git a/apps/blank-app/.gitignore b/apps/blank-app/.gitignore
new file mode 100644
index 00000000..a547bf36
--- /dev/null
+++ b/apps/blank-app/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/apps/blank-app/README.md b/apps/blank-app/README.md
new file mode 100644
index 00000000..9af9c053
--- /dev/null
+++ b/apps/blank-app/README.md
@@ -0,0 +1,32 @@
+# Nimbus Blank App Template
+
+This directory serves as a template for creating basic applications that utilize
+Nimbus. It provides a starting point for new app development within the Nimbus
+ecosystem.
+
+## Creating a New App
+
+To create a new application (e.g., `fancy-app`) based on this template, follow
+these steps:
+
+1. **Duplicate the folder:** Copy the entire `blank-app` directory within the
+ `apps` directory.
+2. **Rename:** Rename the duplicated folder to your desired app name in
+ kebab-case (e.g., `fancy-app`).
+3. **Update `package.json`:** Open the `package.json` file inside your new app
+ folder (e.g., `apps/fancy-app/package.json`) and change the `name` property
+ to match your folder name (e.g., `"name": "fancy-app"`).
+4. **Install dependencies:** Run `pnpm install` from the root directory of the
+ repository. This will install dependencies for all workspaces, including
+ your new app.
+5. **Navigate to your app:** Change your current directory to your new app's
+ folder (e.g., `cd apps/fancy-app`).
+6. **Start the development server:** Run `pnpm dev` to start the Vite
+ development server for your application.
+
+> [!NOTE] This template is based on Vite's `react-swc-ts` template with minor
+> adjustments:
+>
+> 1. The `package.json` includes references to Nimbus catalog dependencies.
+> 2. The default ESLint configuration generated by Vite has been removed, as a
+> root-level ESLint configuration is already present in the repository.
diff --git a/apps/blank-app/index.html b/apps/blank-app/index.html
new file mode 100644
index 00000000..566defe4
--- /dev/null
+++ b/apps/blank-app/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Nimbus + Vite + TS
+
+
+
+
+
+
diff --git a/apps/blank-app/package.json b/apps/blank-app/package.json
new file mode 100644
index 00000000..b11a519d
--- /dev/null
+++ b/apps/blank-app/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "blank-app",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "lint": "eslint .",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "react": "catalog:react",
+ "react-dom": "catalog:react",
+ "@commercetools/nimbus": "workspace:*",
+ "@commercetools/nimbus-icons": "workspace:*"
+ },
+ "devDependencies": {
+ "@eslint/js": "catalog:tooling",
+ "@types/react": "catalog:react",
+ "@types/react-dom": "catalog:react",
+ "@vitejs/plugin-react-swc": "catalog:tooling",
+ "eslint": "catalog:tooling",
+ "eslint-plugin-react-hooks": "catalog:tooling",
+ "eslint-plugin-react-refresh": "catalog:tooling",
+ "globals": "catalog:tooling",
+ "typescript": "catalog:tooling",
+ "typescript-eslint": "catalog:tooling",
+ "vite": "catalog:tooling"
+ }
+}
diff --git a/apps/blank-app/public/cococube.svg b/apps/blank-app/public/cococube.svg
new file mode 100644
index 00000000..79d31170
--- /dev/null
+++ b/apps/blank-app/public/cococube.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/apps/blank-app/src/app.tsx b/apps/blank-app/src/app.tsx
new file mode 100644
index 00000000..a4ff67ca
--- /dev/null
+++ b/apps/blank-app/src/app.tsx
@@ -0,0 +1,43 @@
+import {
+ Box,
+ Flex,
+ Heading,
+ Text,
+ useColorMode,
+ Button,
+} from "@commercetools/nimbus";
+
+import { CommercetoolsCube } from "@commercetools/nimbus-icons";
+
+export const App = () => {
+ const { colorMode, toggleColorMode } = useColorMode();
+
+ return (
+
+
+
+
+
+ @commercetools/nimbus
+
+ Nimbus + Vite + TS
+
+
+ Switch to {colorMode === "light" ? "dark" : "light"} theme
+
+
+
+ );
+};
diff --git a/apps/blank-app/src/main.tsx b/apps/blank-app/src/main.tsx
new file mode 100644
index 00000000..ea23b498
--- /dev/null
+++ b/apps/blank-app/src/main.tsx
@@ -0,0 +1,12 @@
+import { StrictMode } from "react";
+import { createRoot } from "react-dom/client";
+import { App } from "./app";
+import { NimbusProvider } from "@commercetools/nimbus";
+
+createRoot(document.getElementById("root")!).render(
+
+
+
+
+
+);
diff --git a/apps/blank-app/src/vite-env.d.ts b/apps/blank-app/src/vite-env.d.ts
new file mode 100644
index 00000000..11f02fe2
--- /dev/null
+++ b/apps/blank-app/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/apps/blank-app/tsconfig.app.json b/apps/blank-app/tsconfig.app.json
new file mode 100644
index 00000000..358ca9ba
--- /dev/null
+++ b/apps/blank-app/tsconfig.app.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["src"]
+}
diff --git a/apps/blank-app/tsconfig.json b/apps/blank-app/tsconfig.json
new file mode 100644
index 00000000..1ffef600
--- /dev/null
+++ b/apps/blank-app/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
diff --git a/apps/blank-app/tsconfig.node.json b/apps/blank-app/tsconfig.node.json
new file mode 100644
index 00000000..db0becc8
--- /dev/null
+++ b/apps/blank-app/tsconfig.node.json
@@ -0,0 +1,24 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "target": "ES2022",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/apps/blank-app/vite.config.ts b/apps/blank-app/vite.config.ts
new file mode 100644
index 00000000..2328e170
--- /dev/null
+++ b/apps/blank-app/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react-swc'
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [react()],
+})
diff --git a/package.json b/package.json
index a8bd073f..96f20942 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"private": true,
"workspaces": [
"packages/*",
- "apps/docs"
+ "apps/*"
],
"preconstruct": {
"packages": [
diff --git a/packages/nimbus-icons/src/custom-icons/commercetools-cube.tsx b/packages/nimbus-icons/src/custom-icons/commercetools-cube.tsx
new file mode 100644
index 00000000..750187a6
--- /dev/null
+++ b/packages/nimbus-icons/src/custom-icons/commercetools-cube.tsx
@@ -0,0 +1,22 @@
+import type { SVGProps } from "react";
+import { Ref, forwardRef } from "react";
+
+const CubeSvg = (props: SVGProps, ref: Ref) => (
+
+
+
+);
+
+export const CommercetoolsCube = forwardRef(CubeSvg);
diff --git a/packages/nimbus-icons/src/index.ts b/packages/nimbus-icons/src/index.ts
index 014c6853..a623c363 100644
--- a/packages/nimbus-icons/src/index.ts
+++ b/packages/nimbus-icons/src/index.ts
@@ -2,3 +2,4 @@ export * from "./material-icons";
export { Figma } from "./custom-icons/figma";
export { Github } from "./custom-icons/github";
+export { CommercetoolsCube } from "./custom-icons/commercetools-cube";
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 69918e64..6ea026ce 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -209,6 +209,55 @@ importers:
specifier: catalog:tooling
version: 3.1.1(@types/debug@4.1.12)(@types/node@22.14.0)(@vitest/browser@3.1.1)(msw@2.7.0(@types/node@22.14.0)(typescript@5.8.3))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
+ apps/blank-app:
+ dependencies:
+ '@commercetools/nimbus':
+ specifier: workspace:*
+ version: link:../../packages/nimbus
+ '@commercetools/nimbus-icons':
+ specifier: workspace:*
+ version: link:../../packages/nimbus-icons
+ react:
+ specifier: catalog:react
+ version: 18.3.1
+ react-dom:
+ specifier: catalog:react
+ version: 18.3.1(react@18.3.1)
+ devDependencies:
+ '@eslint/js':
+ specifier: catalog:tooling
+ version: 9.24.0
+ '@types/react':
+ specifier: catalog:react
+ version: 18.3.18
+ '@types/react-dom':
+ specifier: catalog:react
+ version: 18.3.5(@types/react@18.3.18)
+ '@vitejs/plugin-react-swc':
+ specifier: catalog:tooling
+ version: 3.8.1(vite@6.2.6(@types/node@22.14.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))
+ eslint:
+ specifier: catalog:tooling
+ version: 9.24.0
+ eslint-plugin-react-hooks:
+ specifier: catalog:tooling
+ version: 5.2.0(eslint@9.24.0)
+ eslint-plugin-react-refresh:
+ specifier: catalog:tooling
+ version: 0.4.19(eslint@9.24.0)
+ globals:
+ specifier: catalog:tooling
+ version: 16.0.0
+ typescript:
+ specifier: catalog:tooling
+ version: 5.8.3
+ typescript-eslint:
+ specifier: catalog:tooling
+ version: 8.29.1(eslint@9.24.0)(typescript@5.8.3)
+ vite:
+ specifier: catalog:tooling
+ version: 6.2.6(@types/node@22.14.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
+
apps/docs:
dependencies:
'@codemirror/theme-one-dark':
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index f076bdef..74a30b60 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,6 +1,6 @@
packages:
- "packages/*"
- - "apps/docs"
+ - "apps/*"
catalogs:
# a dependency that exists in multiple packages can be managed