diff --git a/angular.json b/angular.json
index d04b6ec9..9c2ebca9 100644
--- a/angular.json
+++ b/angular.json
@@ -33,7 +33,10 @@
"node_modules/@fortawesome/fontawesome-free/css/all.min.css",
"src/styles.scss"
],
- "scripts": []
+ "scripts": [],
+ "stylePreprocessorOptions": {
+ "includePaths": ["projects/ppwcode/ng-ppw-ds"]
+ }
},
"configurations": {
"production": {
@@ -521,6 +524,32 @@
}
}
}
+ },
+ "@ppwcode/ng-ppw-ds": {
+ "projectType": "library",
+ "root": "projects/ppwcode/ng-ppw-ds",
+ "sourceRoot": "projects/ppwcode/ng-ppw-ds/src",
+ "prefix": "lib",
+ "architect": {
+ "build": {
+ "builder": "@angular/build:ng-packagr",
+ "configurations": {
+ "production": {
+ "tsConfig": "projects/ppwcode/ng-ppw-ds/tsconfig.lib.prod.json"
+ },
+ "development": {
+ "tsConfig": "projects/ppwcode/ng-ppw-ds/tsconfig.lib.json"
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "test": {
+ "builder": "@angular/build:unit-test",
+ "options": {
+ "tsConfig": "projects/ppwcode/ng-ppw-ds/tsconfig.spec.json"
+ }
+ }
+ }
}
},
"cli": {
diff --git a/projects/ppwcode/ng-ppw-ds/README.md b/projects/ppwcode/ng-ppw-ds/README.md
new file mode 100644
index 00000000..58bb2c45
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/README.md
@@ -0,0 +1,3 @@
+# PeopleWare Design System
+
+This library holds the official PeopleWare Design System implementation for Angular.
diff --git a/projects/ppwcode/ng-ppw-ds/ng-package.json b/projects/ppwcode/ng-ppw-ds/ng-package.json
new file mode 100644
index 00000000..dbb5cefe
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/ng-package.json
@@ -0,0 +1,10 @@
+{
+ "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
+ "dest": "../../../dist/ppwcode/ng-ppw-ds",
+ "lib": {
+ "entryFile": "src/public-api.ts"
+ },
+ "assets": [
+ "ppw-ds.scss"
+ ]
+}
diff --git a/projects/ppwcode/ng-ppw-ds/package.json b/projects/ppwcode/ng-ppw-ds/package.json
new file mode 100644
index 00000000..80fc4070
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@ppwcode/ng-ppw-ds",
+ "version": "0.0.1",
+ "peerDependencies": {
+ "@angular/common": "^20.0.0",
+ "@angular/core": "^20.0.0"
+ },
+ "dependencies": {
+ "tslib": "^2.3.0"
+ },
+ "sideEffects": false
+}
diff --git a/projects/ppwcode/ng-ppw-ds/ppw-ds.scss b/projects/ppwcode/ng-ppw-ds/ppw-ds.scss
new file mode 100644
index 00000000..cfacd020
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/ppw-ds.scss
@@ -0,0 +1,2 @@
+@use 'src/lib/scss/shapes';
+@use 'src/lib/scss/spacings';
diff --git a/projects/ppwcode/ng-ppw-ds/src/lib/docs/Shapes.mdx b/projects/ppwcode/ng-ppw-ds/src/lib/docs/Shapes.mdx
new file mode 100644
index 00000000..0b7d36a5
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/src/lib/docs/Shapes.mdx
@@ -0,0 +1,18 @@
+import { Meta, Canvas } from '@storybook/addon-docs/blocks';
+import * as ShapesStories from '../stories/shapes.stories'
+
+
+
+# Shapes
+
+Shape defines the geometry of components throughout the design system, primarily through corner radius and outline style. Consistent shape tokens create a cohesive visual language, reinforce brand identity, and ensure components such as buttons, cards, inputs, and dialogs share a unified appearance. By using shape tokens instead of hardcoded values, the overall look and feel can be updated consistently across the entire application.
+
+## Usage
+
+The ppwcode design system provides CSS tokens that can be used for consistent shapes in your application.
+
+The CSS tokens follow the syntax `--ppw-ds-radius-[level]`, where `[level]` indicates a shaping level.
+
+A shaping level is one of the following demonstrated levels, where each greater level means a more rounded shape.
+
+
diff --git a/projects/ppwcode/ng-ppw-ds/src/lib/docs/Spacings.mdx b/projects/ppwcode/ng-ppw-ds/src/lib/docs/Spacings.mdx
new file mode 100644
index 00000000..3964ed44
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/src/lib/docs/Spacings.mdx
@@ -0,0 +1,20 @@
+import { Meta, Canvas } from '@storybook/addon-docs/blocks';
+import * as SpacingsStories from '../stories/spacings.stories'
+
+
+
+# Spacing
+
+Spacing defines the consistent use of whitespace throughout the design system. Spacing tokens provide a standardized scale for margins, padding, gaps, and layout dimensions, creating balanced, readable, and predictable interfaces. By using spacing tokens instead of hardcoded values, layouts remain consistent, responsive, and easy to maintain across all components and applications.
+
+## Usage
+
+The ppwcode design system provides linear and explicit CSS tokens that can be used for consistent spacing in your application.
+
+The CSS tokens follow the syntax `--ppw-ds-spacing-[level]`, where `[level]` indicates a spacing level.
+
+A linear spacing level is the multiplication of 4. Level 0 thus means 0px, where level 5 means 20px.
+
+
+
+The tokens `--ppw-ds-spacing-1px` and `--ppw-ds-spacing-2px` are explicit and intended for usage where space is limited and decreasing density would otherwise bring visual items far too close to each other.
diff --git a/projects/ppwcode/ng-ppw-ds/src/lib/scss/_shapes.scss b/projects/ppwcode/ng-ppw-ds/src/lib/scss/_shapes.scss
new file mode 100644
index 00000000..38820638
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/src/lib/scss/_shapes.scss
@@ -0,0 +1,13 @@
+$_radii: (
+ 'none': 0,
+ 'small': 4px,
+ 'medium': 8px,
+ 'large': 20px,
+ 'full': 1000px
+);
+
+:root {
+ @each $radius, $value in $_radii {
+ --ppw-ds-radius-#{$radius}: #{$value};
+ }
+}
diff --git a/projects/ppwcode/ng-ppw-ds/src/lib/scss/_spacings.scss b/projects/ppwcode/ng-ppw-ds/src/lib/scss/_spacings.scss
new file mode 100644
index 00000000..6959f4ab
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/src/lib/scss/_spacings.scss
@@ -0,0 +1,14 @@
+$_base-spacing: 4px;
+
+:root {
+ // The following CSS tokens are explicit spacing tokens that don't take part in the base-spacing linearity.
+ // They are a specifically targeted at situations where space is limited and decreasing density would otherwise
+ // bring visual items far too close to each other.
+ --ppw-ds-spacing-1px: 1px;
+ --ppw-ds-spacing-2px: 2px;
+
+ // Generate CSS tokens for a linear scale from 0 to 20 for increased spacing.
+ @for $i from 0 through 20 {
+ --ppw-ds-spacing-#{$i}: #{$i * $_base-spacing};
+ }
+}
diff --git a/projects/ppwcode/ng-ppw-ds/src/lib/stories/shapes.stories.ts b/projects/ppwcode/ng-ppw-ds/src/lib/stories/shapes.stories.ts
new file mode 100644
index 00000000..1813c3a5
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/src/lib/stories/shapes.stories.ts
@@ -0,0 +1,48 @@
+import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'
+import { Component } from '@angular/core'
+
+const shapes = ['none', 'small', 'medium', 'large', 'full']
+
+@Component({
+ selector: 'ppw-shapes-example',
+ template: `
+ @for (shape of shapes; track shape) {
+
{{ shape }}
+ }
+ `,
+ styles: `
+ :host {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ grid-gap: 16px;
+ }
+
+ .box {
+ display: inline-flex;
+ flex-direction: column;
+ align-items: center;
+ background: var(--ppw-primary-color);
+ color: var(--ppw-primary-contrast-color);
+ padding: 16px;
+ width: 250px;
+ }
+ `
+})
+export class ShapesExampleComponent {
+ public readonly shapes = shapes
+}
+
+const meta: Meta = {
+ title: 'ng-ppw-ds/Shapes',
+ component: ShapesExampleComponent,
+ decorators: [
+ moduleMetadata({
+ imports: [ShapesExampleComponent]
+ })
+ ]
+}
+
+export default meta
+type Story = StoryObj
+
+export const AllLevels: Story = {}
diff --git a/projects/ppwcode/ng-ppw-ds/src/lib/stories/spacings.stories.ts b/projects/ppwcode/ng-ppw-ds/src/lib/stories/spacings.stories.ts
new file mode 100644
index 00000000..5e84cc36
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/src/lib/stories/spacings.stories.ts
@@ -0,0 +1,73 @@
+import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'
+import { Component } from '@angular/core'
+
+const spacings = Array.from({ length: 21 }, (_, i) => i)
+
+@Component({
+ selector: 'ppw-spacings-example',
+ template: `
+ @for (level of spacings; track level) {
+
+
{{ level }}
+
{{ level * 4 }}px
+
+ }
+ `,
+ styles: `
+ :host {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ grid-gap: 16px;
+ }
+
+ .boxes-wrapper {
+ display: flex;
+ flex-direction: row;
+ }
+
+ .box {
+ display: inline-flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 16px;
+ width: 25px;
+
+ &--primary {
+ background: var(--ppw-primary-color);
+ color: var(--ppw-primary-contrast-color);
+ }
+
+ &--secondary {
+ background: var(--ppw-secondary-color);
+ color: var(--ppw-secondary-contrast-color);
+ }
+ }
+ `
+})
+export class SpacingsExampleComponent {
+ public readonly spacings = spacings
+}
+
+const meta: Meta = {
+ title: 'ng-ppw-ds/Spacings',
+ component: SpacingsExampleComponent,
+ decorators: [
+ moduleMetadata({
+ imports: [SpacingsExampleComponent]
+ })
+ ],
+ parameters: {
+ docs: {
+ description: {
+ component: `
+
+ `
+ }
+ }
+ }
+}
+
+export default meta
+type Story = StoryObj
+
+export const AllLevels: Story = {}
diff --git a/projects/ppwcode/ng-ppw-ds/src/public-api.ts b/projects/ppwcode/ng-ppw-ds/src/public-api.ts
new file mode 100644
index 00000000..2d6a7810
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/src/public-api.ts
@@ -0,0 +1,5 @@
+/*
+ * Public API Surface of ng-ppw-ds
+ */
+
+export {}
diff --git a/projects/ppwcode/ng-ppw-ds/tsconfig.lib.json b/projects/ppwcode/ng-ppw-ds/tsconfig.lib.json
new file mode 100644
index 00000000..fdcd9fe2
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/tsconfig.lib.json
@@ -0,0 +1,15 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+ "extends": "../../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../out-tsc/lib",
+ "declaration": true,
+ "declarationMap": true,
+ "inlineSources": true,
+ "types": []
+ },
+ "exclude": [
+ "**/*.spec.ts"
+ ]
+}
diff --git a/projects/ppwcode/ng-ppw-ds/tsconfig.lib.prod.json b/projects/ppwcode/ng-ppw-ds/tsconfig.lib.prod.json
new file mode 100644
index 00000000..9215caac
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/tsconfig.lib.prod.json
@@ -0,0 +1,11 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+ "extends": "./tsconfig.lib.json",
+ "compilerOptions": {
+ "declarationMap": false
+ },
+ "angularCompilerOptions": {
+ "compilationMode": "partial"
+ }
+}
diff --git a/projects/ppwcode/ng-ppw-ds/tsconfig.spec.json b/projects/ppwcode/ng-ppw-ds/tsconfig.spec.json
new file mode 100644
index 00000000..35d15edb
--- /dev/null
+++ b/projects/ppwcode/ng-ppw-ds/tsconfig.spec.json
@@ -0,0 +1,15 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+ "extends": "../../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../out-tsc/spec",
+ "types": [
+ "jasmine"
+ ]
+ },
+ "include": [
+ "**/*.spec.ts",
+ "**/*.d.ts"
+ ]
+}
diff --git a/projects/ppwcode/ng-wireframe/src/stories/Configure.mdx b/projects/ppwcode/ng-wireframe/src/stories/Configure.mdx
index a11ff606..0085c467 100644
--- a/projects/ppwcode/ng-wireframe/src/stories/Configure.mdx
+++ b/projects/ppwcode/ng-wireframe/src/stories/Configure.mdx
@@ -23,6 +23,11 @@ A collection of reusable UI components for data display and user interaction.
- **Loader**: A simple yet customizable loading spinner for asynchronous operations.
- **Dashboard Items Table**: A responsive grid layout designed specifically for hosting dashboard summary items.
+### 🎨 ng-ppw-ds
+The PeopleWare Design System provides design tokens for consistent styling across the SDK and consuming applications.
+- **Shapes**: Radius tokens for consistent component geometry.
+- **Spacings**: A 4px-based scale for consistent margins, padding, gaps, and layout dimensions.
+
### 💬 ng-dialogs
Utilities and reusable dialogs to simplify common user interaction patterns.
- **Confirmation Dialog**: A flexible dialog for standard "confirm/cancel" workflows.
diff --git a/scripts/ci/build-libs.sh b/scripts/ci/build-libs.sh
index 27021624..b39b7b28 100755
--- a/scripts/ci/build-libs.sh
+++ b/scripts/ci/build-libs.sh
@@ -1,7 +1,7 @@
#!/bin/bash
export NODE_ENV="ci"
-declare -a LIBRARIES_LIST=("ng-utils" "ng-common" "ng-common-components" "ng-async" "ng-dialogs" "ng-forms" "ng-router" "ng-state-management" "ng-unit-testing" "ng-wireframe" "ng-sdk")
+declare -a LIBRARIES_LIST=("ng-ppw-ds" "ng-utils" "ng-common" "ng-common-components" "ng-async" "ng-dialogs" "ng-forms" "ng-router" "ng-state-management" "ng-unit-testing" "ng-wireframe" "ng-sdk")
declare -a LIBRARIES_COUNT=${#LIBRARIES_LIST[@]}
# Loop over libs
diff --git a/scripts/ci/get-libs.sh b/scripts/ci/get-libs.sh
deleted file mode 100644
index a0c4900f..00000000
--- a/scripts/ci/get-libs.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-
-# This script fetches all the libraries in the folders and sets environment variables to be used by
-# other scripts in CI.
-
-cd projects/ppwcode/
-export LIBRARIES_LIST=`ls -d */ | tr -d /`
-cd ../
-
-export LIBRARIES_COUNT=`wc -w <<< ${LIBRARIES_LIST}`
-
-# Output for better debuggability
-echo 'Found libraries:' ${LIBRARIES_LIST}
-echo 'Libraries count:' ${LIBRARIES_COUNT}
diff --git a/src/styles.scss b/src/styles.scss
index a679d286..dad1aa1c 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -1,5 +1,6 @@
/* You can add global styles to this file, and also import other style files */
@use '@angular/material' as mat;
+@use 'ppw-ds';
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
@@ -70,6 +71,11 @@ $ppw-ui-theme: mat.m2-define-light-theme(
html,
body {
height: 100%;
+
+ --ppw-primary-color: #18428c;
+ --ppw-primary-contrast-color: white;
+ --ppw-secondary-color: #6eb343;
+ --ppw-secondary-contrast-color: white;
}
body {
@@ -85,17 +91,17 @@ body {
--ppw-confirmation-dialog-header-background-color: #{mat.m2-get-color-from-palette($ppw-primary-palette, 500)};
--ppw-confirmation-dialog-header-text-color: #{mat.m2-get-contrast-color-from-palette($ppw-primary-palette, 500)};
- --ppw-expandable-card-header-text-color: white;
- --ppw-expandable-card-header-background-color: #6eb343;
- --ppw-expandable-card-header-indicator-color: white;
+ --ppw-expandable-card-header-text-color: var(--ppw-secondary-contrast-color);
+ --ppw-expandable-card-header-background-color: var(--ppw-secondary-color);
+ --ppw-expandable-card-header-indicator-color: var(--ppw-secondary-contrast-color);
--ppw-loader-content-padding: 16px;
--ppw-message-bar-warning-text-color: black;
- --ppw-sidenav-background-color: #18428c;
- --ppw-sidenav-navigation-item-icon-color: #6eb343;
- --ppw-sidenav-close-button-color: white;
+ --ppw-sidenav-background-color: var(--ppw-primary-color);
+ --ppw-sidenav-navigation-item-icon-color: var(--ppw-secondary-color);
+ --ppw-sidenav-close-button-color: var(--ppw-primary-contrast-color);
--ppw-sidenav-navigation-item-external-icon-color: rgba(255, 255, 255, 0.15);
--ppw-table-row-highlight-background-color: rgba(0, 0, 255, 0.03);
@@ -103,26 +109,26 @@ body {
--ppw-table-row-highlight-sticky-background-color: rgb(239, 239, 255);
--ppw-toolbar-page-title-font-size: 20px;
- --ppw-toolbar-page-title-text-color: #18428c;
+ --ppw-toolbar-page-title-text-color: var(--ppw-primary-color);
--ppw-dashboard-items-table-width: 750px;
- --ppw-dashboard-items-table-primary-color: #18428c;
- --ppw-dashboard-items-table-background-color: #6eb343;
+ --ppw-dashboard-items-table-primary-color: var(--ppw-primary-color);
+ --ppw-dashboard-items-table-background-color: var(--ppw-secondary-color);
--ppw-dashboard-wrapper-container-vertical-margin: 32px;
--ppw-dashboard-items-card-margin: 8px;
--ppw-breadcrumb-background-color: whitesmoke;
- --ppw-breadcrumb-text-color: #18428c;
+ --ppw-breadcrumb-text-color: var(--ppw-primary-color);
--ppw-breadcrumb-text-hover-color: #6390df;
}
ppw-wireframe.flat {
- background: #18428c;
+ background: var(--ppw-primary-color);
--ppw-app-wireframe-drawer-border: none;
- --ppw-page-container-background: #18428c;
- --ppw-toolbar-background: #18428c;
- --ppw-toolbar-page-title-text-color: white;
+ --ppw-page-container-background: var(--ppw-primary-color);
+ --ppw-toolbar-background: var(--ppw-primary-color);
+ --ppw-toolbar-page-title-text-color: var(--ppw-primary-contrast-color);
--ppw-toolbar-border-bottom: none;
--ppw-toolbar-box-shadow: none;
}
@@ -255,7 +261,7 @@ div.page-toggles {
mat-slide-toggle {
div.mdc-form-field {
label {
- color: white;
+ color: var(--ppw-primary-contrast-color);
}
}
}
diff --git a/tsconfig.angular.json b/tsconfig.angular.json
index eb54bb6d..bf1485db 100644
--- a/tsconfig.angular.json
+++ b/tsconfig.angular.json
@@ -8,6 +8,7 @@
"@ppwcode/ng-common-components": ["./dist/ppwcode/ng-common-components"],
"@ppwcode/ng-dialogs": ["./dist/ppwcode/ng-dialogs"],
"@ppwcode/ng-forms": ["./dist/ppwcode/ng-forms"],
+ "@ppwcode/ng-ppw-ds": ["./dist/ppwcode/ng-ppw-ds"],
"@ppwcode/ng-router": ["./dist/ppwcode/ng-router"],
"@ppwcode/ng-state-management": ["./dist/ppwcode/ng-state-management"],
"@ppwcode/ng-unit-testing": ["./dist/ppwcode/ng-unit-testing"],
diff --git a/tsconfig.json b/tsconfig.json
index c1cbdafa..bf93ecee 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -9,6 +9,7 @@
"@ppwcode/ng-common-components": ["./projects/ppwcode/ng-common-components/src/public-api"],
"@ppwcode/ng-dialogs": ["./projects/ppwcode/ng-dialogs/src/public-api"],
"@ppwcode/ng-forms": ["./projects/ppwcode/ng-forms/src/public-api"],
+ "@ppwcode/ng-ppw-ds": ["./projects/ppwcode/ng-ppw-ds/src/public-api"],
"@ppwcode/ng-router": ["./projects/ppwcode/ng-router/src/public-api"],
"@ppwcode/ng-state-management": ["./projects/ppwcode/ng-state-management/src/public-api"],
"@ppwcode/ng-unit-testing": ["./projects/ppwcode/ng-unit-testing/src/public-api"],