@ng-zen/cli 19.1.0 → 19.2.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/deploy.yml +13 -5
- package/.github/workflows/release.yml +1 -0
- package/CHANGELOG.md +14 -0
- package/README.md +7 -2
- package/angular.json +2 -2
- package/eslint.config.js +34 -1
- package/package.json +44 -49
- package/src/schematics/components/components-generator.ts +1 -1
- package/src/schematics/components/files/button/button.component.scss +6 -5
- package/src/schematics/components/files/button/button.stories.ts +1 -0
- package/src/schematics/components/files/checkbox/checkbox.component.scss +1 -1
- package/src/schematics/components/files/checkbox/checkbox.component.ts +1 -1
- package/src/schematics/components/files/checkbox/checkbox.stories.ts +1 -0
- package/src/schematics/components/files/divider/divider.component.scss +52 -0
- package/src/schematics/components/files/divider/divider.component.spec.ts +22 -0
- package/src/schematics/components/files/divider/divider.component.ts +58 -0
- package/src/schematics/components/files/divider/divider.stories.ts +69 -0
- package/src/schematics/components/files/divider/index.ts +1 -0
- package/src/schematics/components/files/input/input.component.scss +1 -1
- package/src/schematics/components/files/input/input.stories.ts +1 -0
- package/src/schematics/components/files/switch/switch.component.scss +2 -2
- package/src/schematics/components/files/switch/switch.stories.ts +1 -0
- package/src/schematics/components/files/textarea/textarea.component.scss +1 -1
- package/src/schematics/components/files/textarea/textarea.stories.ts +1 -0
- package/src/schematics/components/schema.json +1 -1
- package/src/schematics/ng-add/index.ts +4 -6
- package/src/schematics/ng-add/ng-zen-generator.ts +3 -3
- package/src/utils/apply-file-template.util.ts +1 -0
- package/src/utils/index.ts +0 -1
- package/projects/schematic-builder/builders/builders.json +0 -9
- package/projects/schematic-builder/builders/index.js +0 -100
- package/projects/schematic-builder/builders/schema.json +0 -18
- package/projects/schematic-builder/package.json +0 -11
- package/src/utils/add-path-to-tsconfig.util.ts +0 -50
|
@@ -2,7 +2,8 @@ name: Deploy Storybook to github pages
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
|
-
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*.*.*'
|
|
6
7
|
workflow_dispatch:
|
|
7
8
|
|
|
8
9
|
env:
|
|
@@ -18,14 +19,21 @@ jobs:
|
|
|
18
19
|
deploy:
|
|
19
20
|
runs-on: ubuntu-latest
|
|
20
21
|
steps:
|
|
21
|
-
-
|
|
22
|
-
|
|
22
|
+
- name: Checkout code
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
- name: Enable Corepack
|
|
25
|
+
run: corepack enable
|
|
26
|
+
- name: Setup pnpm
|
|
27
|
+
uses: pnpm/action-setup@v4
|
|
23
28
|
with:
|
|
24
29
|
version: ${{ env.PNPM_VERSION }}
|
|
25
|
-
-
|
|
30
|
+
- name: Setup Node.js
|
|
31
|
+
uses: actions/setup-node@v4
|
|
26
32
|
with:
|
|
27
33
|
node-version: ${{ env.NODE_VERSION }}
|
|
28
|
-
|
|
34
|
+
cache: 'pnpm'
|
|
35
|
+
- name: Build and deploy Storybook
|
|
36
|
+
id: build-publish
|
|
29
37
|
uses: bitovi/github-actions-storybook-to-github-pages@v1.0.3
|
|
30
38
|
with:
|
|
31
39
|
install_command: pnpm install --frozen-lockfile
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 19.2.0-next.1 (2025-05-23)
|
|
2
|
+
|
|
3
|
+
* chore(dependencies): update dependencies (#187) ([7028a9e](https://github.com/kstepien3/ng-zen/commit/7028a9e)), closes [#187](https://github.com/kstepien3/ng-zen/issues/187)
|
|
4
|
+
* chore(dependencies): update ngx-schematic-builder to v0.2.0 (#183) ([5ea0cea](https://github.com/kstepien3/ng-zen/commit/5ea0cea)), closes [#183](https://github.com/kstepien3/ng-zen/issues/183)
|
|
5
|
+
* chore(workflow): update deploy workflow for tag-based triggering (#166) ([0fea522](https://github.com/kstepien3/ng-zen/commit/0fea522)), closes [#166](https://github.com/kstepien3/ng-zen/issues/166) [#165](https://github.com/kstepien3/ng-zen/issues/165)
|
|
6
|
+
* chore(workflows): disable persist-credentials in release workflow (#188) ([b784e47](https://github.com/kstepien3/ng-zen/commit/b784e47)), closes [#188](https://github.com/kstepien3/ng-zen/issues/188)
|
|
7
|
+
* feat(divider): add zen-divider component (#186) ([c021773](https://github.com/kstepien3/ng-zen/commit/c021773)), closes [#186](https://github.com/kstepien3/ng-zen/issues/186)
|
|
8
|
+
* style(components): update outline styles (#184) ([5737a15](https://github.com/kstepien3/ng-zen/commit/5737a15)), closes [#184](https://github.com/kstepien3/ng-zen/issues/184)
|
|
9
|
+
* fix(schematics/ng-add): run other schematics after installation (#177) ([5cb1be4](https://github.com/kstepien3/ng-zen/commit/5cb1be4)), closes [#177](https://github.com/kstepien3/ng-zen/issues/177)
|
|
10
|
+
* ci(eslint): fix plugins and configure linting rules (#176) ([5e93a09](https://github.com/kstepien3/ng-zen/commit/5e93a09)), closes [#176](https://github.com/kstepien3/ng-zen/issues/176)
|
|
11
|
+
* build(deps-dev): bump typescript from 5.7.3 to 5.8.3 (#154) ([3ebe49f](https://github.com/kstepien3/ng-zen/commit/3ebe49f)), closes [#154](https://github.com/kstepien3/ng-zen/issues/154)
|
|
12
|
+
* build(ngx-schematic-builder): migrate the custom builder (#175) ([c7d19eb](https://github.com/kstepien3/ng-zen/commit/c7d19eb)), closes [#175](https://github.com/kstepien3/ng-zen/issues/175)
|
|
13
|
+
* Merge remote-tracking branch 'origin/next' into develop ([f581d01](https://github.com/kstepien3/ng-zen/commit/f581d01))
|
|
14
|
+
|
|
1
15
|
## [19.1.0](https://github.com/kstepien3/ng-zen/compare/v19.0.0...v19.1.0) (2025-04-27)
|
|
2
16
|
|
|
3
17
|
### 🚀 New Features
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
Generate modern, customizable Angular UI components and elements directly into your project 🚀
|
|
13
13
|
|
|
14
|
-
Built with best practices and developer experience in mind 💡
|
|
14
|
+
Built with the best practices and developer experience in mind 💡
|
|
15
15
|
|
|
16
16
|
## Table of Contents
|
|
17
17
|
|
|
@@ -27,7 +27,8 @@ Built with best practices and developer experience in mind 💡
|
|
|
27
27
|
10. [Contributing](#contributing)
|
|
28
28
|
11. [License](#license)
|
|
29
29
|
12. [Author](#author)
|
|
30
|
-
13. [
|
|
30
|
+
13. [See also](#see-also)
|
|
31
|
+
14. [FAQ](#faq)
|
|
31
32
|
|
|
32
33
|
## Features
|
|
33
34
|
|
|
@@ -148,6 +149,10 @@ Maintained by Konrad Stępień.
|
|
|
148
149
|
- LinkedIn: [Konrad Stępień](https://www.linkedin.com/in/konradstepien/) 👥
|
|
149
150
|
- Email: [kord.stp@gmail.com](mailto:kord.stp@gmail.com?subject=%5BNG-ZEN%5D%20Query) 📨
|
|
150
151
|
|
|
152
|
+
## See also
|
|
153
|
+
|
|
154
|
+
- [ngx-schematic-builder](https://github.com/kstepien3/ngx-schematic-builder) - A custom Angular builder for compiling and bundling Angular schematics.
|
|
155
|
+
|
|
151
156
|
## FAQ
|
|
152
157
|
|
|
153
158
|
### How do I customize a generated component?
|
package/angular.json
CHANGED
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"prefix": "zen",
|
|
21
21
|
"architect": {
|
|
22
22
|
"build": {
|
|
23
|
-
"builder": "
|
|
23
|
+
"builder": "ngx-schematic-builder:build",
|
|
24
24
|
"options": {
|
|
25
|
-
"files": ["src/**", "README.md", "
|
|
25
|
+
"files": ["src/**", "README.md", "LICENSE", "CHANGELOG.md"],
|
|
26
26
|
"tsConfig": "tsconfig.schematics.json"
|
|
27
27
|
}
|
|
28
28
|
},
|
package/eslint.config.js
CHANGED
|
@@ -2,8 +2,15 @@
|
|
|
2
2
|
const eslint = require('@eslint/js');
|
|
3
3
|
const tseslint = require('typescript-eslint');
|
|
4
4
|
const angular = require('angular-eslint');
|
|
5
|
+
const prettierRecommended = require('eslint-plugin-prettier/recommended');
|
|
6
|
+
const eslintPluginImport = require('eslint-plugin-import');
|
|
7
|
+
const simpleImportSort = require('eslint-plugin-simple-import-sort');
|
|
8
|
+
const unicorn = require('eslint-plugin-unicorn');
|
|
9
|
+
const unusedImports = require('eslint-plugin-unused-imports');
|
|
10
|
+
const storybook = require('eslint-plugin-storybook');
|
|
5
11
|
|
|
6
12
|
module.exports = tseslint.config(
|
|
13
|
+
...storybook.configs['flat/recommended'],
|
|
7
14
|
{
|
|
8
15
|
files: ['**/*.ts'],
|
|
9
16
|
extends: [
|
|
@@ -13,6 +20,12 @@ module.exports = tseslint.config(
|
|
|
13
20
|
...angular.configs.tsRecommended,
|
|
14
21
|
],
|
|
15
22
|
processor: angular.processInlineTemplates,
|
|
23
|
+
plugins: {
|
|
24
|
+
'simple-import-sort': simpleImportSort,
|
|
25
|
+
'import/recommended': eslintPluginImport.flatConfigs,
|
|
26
|
+
unicorn: unicorn,
|
|
27
|
+
'unused-imports': unusedImports,
|
|
28
|
+
},
|
|
16
29
|
rules: {
|
|
17
30
|
'@angular-eslint/directive-selector': [
|
|
18
31
|
'error',
|
|
@@ -30,11 +43,31 @@ module.exports = tseslint.config(
|
|
|
30
43
|
style: 'kebab-case',
|
|
31
44
|
},
|
|
32
45
|
],
|
|
46
|
+
'simple-import-sort/imports': 'warn',
|
|
47
|
+
'simple-import-sort/exports': 'warn',
|
|
48
|
+
'unused-imports/no-unused-imports': 'warn',
|
|
33
49
|
},
|
|
34
50
|
},
|
|
35
51
|
{
|
|
36
52
|
files: ['**/*.html'],
|
|
37
53
|
extends: [...angular.configs.templateRecommended, ...angular.configs.templateAccessibility],
|
|
38
|
-
rules: {
|
|
54
|
+
rules: {
|
|
55
|
+
'@angular-eslint/template/prefer-self-closing-tags': ['error'],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
files: ['**/*.html', '**/*.ts'],
|
|
60
|
+
extends: [prettierRecommended],
|
|
61
|
+
rules: {
|
|
62
|
+
'prettier/prettier': [
|
|
63
|
+
'warn',
|
|
64
|
+
{
|
|
65
|
+
endOfLine: 'auto',
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
ignores: ['!.storybook'],
|
|
39
72
|
}
|
|
40
73
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ng-zen/cli",
|
|
3
|
-
"version": "19.
|
|
3
|
+
"version": "19.2.0-next.1",
|
|
4
4
|
"description": "A CLI tool for generating customizable, modern Angular UI components using schematics.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"ng": "ng",
|
|
@@ -55,77 +55,72 @@
|
|
|
55
55
|
"@angular/core": ">=19.0.0"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@angular-devkit/core": "^19.
|
|
59
|
-
"@angular-devkit/schematics": "^19.
|
|
58
|
+
"@angular-devkit/core": "^19.2.13",
|
|
59
|
+
"@angular-devkit/schematics": "^19.2.13",
|
|
60
60
|
"tslib": "^2.8.1"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@angular-builders/jest": "^19.0.
|
|
64
|
-
"@angular-devkit/architect": "^0.1902.
|
|
65
|
-
"@angular-devkit/build-angular": "^19.
|
|
63
|
+
"@angular-builders/jest": "^19.0.1",
|
|
64
|
+
"@angular-devkit/architect": "^0.1902.13",
|
|
65
|
+
"@angular-devkit/build-angular": "^19.2.13",
|
|
66
66
|
"@angular-devkit/core": "^19.1.7",
|
|
67
|
-
"@angular/animations": "^19.
|
|
68
|
-
"@angular/cli": "^19.
|
|
69
|
-
"@angular/common": "^19.
|
|
70
|
-
"@angular/compiler": "^19.
|
|
71
|
-
"@angular/compiler-cli": "^19.
|
|
72
|
-
"@angular/core": "^19.
|
|
73
|
-
"@angular/forms": "^19.
|
|
74
|
-
"@angular/platform-browser": "^19.
|
|
75
|
-
"@angular/platform-browser-dynamic": "^19.
|
|
76
|
-
"@angular/router": "^19.
|
|
67
|
+
"@angular/animations": "^19.2.12",
|
|
68
|
+
"@angular/cli": "^19.2.13",
|
|
69
|
+
"@angular/common": "^19.2.12",
|
|
70
|
+
"@angular/compiler": "^19.2.12",
|
|
71
|
+
"@angular/compiler-cli": "^19.2.12",
|
|
72
|
+
"@angular/core": "^19.2.12",
|
|
73
|
+
"@angular/forms": "^19.2.12",
|
|
74
|
+
"@angular/platform-browser": "^19.2.12",
|
|
75
|
+
"@angular/platform-browser-dynamic": "^19.2.12",
|
|
76
|
+
"@angular/router": "^19.2.12",
|
|
77
77
|
"@chromatic-com/storybook": "^3.2.6",
|
|
78
|
-
"@commitlint/cli": "^19.
|
|
79
|
-
"@commitlint/config-conventional": "^19.8.
|
|
78
|
+
"@commitlint/cli": "^19.8.1",
|
|
79
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
80
80
|
"@compodoc/compodoc": "^1.1.26",
|
|
81
|
-
"@eslint/js": "^9.
|
|
81
|
+
"@eslint/js": "^9.27.0",
|
|
82
82
|
"@semantic-release/changelog": "^6.0.3",
|
|
83
83
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
84
84
|
"@semantic-release/git": "^10.0.1",
|
|
85
|
-
"@semantic-release/github": "^11.0.
|
|
85
|
+
"@semantic-release/github": "^11.0.2",
|
|
86
86
|
"@semantic-release/npm": "^12.0.1",
|
|
87
87
|
"@semantic-release/release-notes-generator": "^14.0.3",
|
|
88
|
-
"@storybook/addon-docs": "^8.
|
|
89
|
-
"@storybook/addon-essentials": "^8.
|
|
90
|
-
"@storybook/addon-interactions": "^8.
|
|
91
|
-
"@storybook/addon-links": "^8.6.
|
|
92
|
-
"@storybook/addon-onboarding": "^8.
|
|
93
|
-
"@storybook/angular": "^8.
|
|
94
|
-
"@storybook/blocks": "^8.
|
|
95
|
-
"@storybook/test": "^8.
|
|
88
|
+
"@storybook/addon-docs": "^8.6.14",
|
|
89
|
+
"@storybook/addon-essentials": "^8.6.14",
|
|
90
|
+
"@storybook/addon-interactions": "^8.6.14",
|
|
91
|
+
"@storybook/addon-links": "^8.6.14",
|
|
92
|
+
"@storybook/addon-onboarding": "^8.6.14",
|
|
93
|
+
"@storybook/angular": "^8.6.14",
|
|
94
|
+
"@storybook/blocks": "^8.6.14",
|
|
95
|
+
"@storybook/test": "^8.6.14",
|
|
96
96
|
"@types/jest": "29.5.14",
|
|
97
|
-
"angular-eslint": "19.
|
|
98
|
-
"conventional-changelog-conventionalcommits": "^8.0.0",
|
|
97
|
+
"angular-eslint": "19.4.0",
|
|
99
98
|
"copyfiles": "^2.4.1",
|
|
100
99
|
"cpy": "^11.1.0",
|
|
101
|
-
"eslint": "^9.
|
|
102
|
-
"eslint-config-prettier": "^10.
|
|
100
|
+
"eslint": "^9.27.0",
|
|
101
|
+
"eslint-config-prettier": "^10.1.5",
|
|
103
102
|
"eslint-plugin-import": "^2.31.0",
|
|
104
|
-
"eslint-plugin-prettier": "^5.
|
|
103
|
+
"eslint-plugin-prettier": "^5.4.0",
|
|
105
104
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
106
105
|
"eslint-plugin-storybook": "^0.12.0",
|
|
107
|
-
"eslint-plugin-unicorn": "^
|
|
106
|
+
"eslint-plugin-unicorn": "^59.0.1",
|
|
108
107
|
"eslint-plugin-unused-imports": "^4.1.4",
|
|
109
|
-
"execa": "^9.5.
|
|
108
|
+
"execa": "^9.5.3",
|
|
110
109
|
"fs-extra": "^11.3.0",
|
|
111
110
|
"husky": "^9.1.7",
|
|
112
|
-
"jasmine-core": "~5.
|
|
111
|
+
"jasmine-core": "~5.7.1",
|
|
113
112
|
"jest": "^29.7.0",
|
|
114
|
-
"jest-preset-angular": "^14.5.
|
|
113
|
+
"jest-preset-angular": "^14.5.5",
|
|
115
114
|
"nano-staged": "^0.8.0",
|
|
115
|
+
"ngx-schematic-builder": "^0.2.0",
|
|
116
116
|
"prettier": "^3.5.3",
|
|
117
117
|
"prettier-plugin-organize-attributes": "^1.0.0",
|
|
118
|
-
"rxjs": "~7.8.
|
|
119
|
-
"semantic-release": "^24.2.
|
|
120
|
-
"storybook": "^8.
|
|
121
|
-
"stylelint": "^16.
|
|
122
|
-
"stylelint-config-standard-scss": "^
|
|
123
|
-
"typescript": "~5.
|
|
124
|
-
"typescript-eslint": "8.
|
|
125
|
-
},
|
|
126
|
-
"eslintConfig": {
|
|
127
|
-
"extends": [
|
|
128
|
-
"plugin:storybook/recommended"
|
|
129
|
-
]
|
|
118
|
+
"rxjs": "~7.8.2",
|
|
119
|
+
"semantic-release": "^24.2.4",
|
|
120
|
+
"storybook": "^8.6.14",
|
|
121
|
+
"stylelint": "^16.19.1",
|
|
122
|
+
"stylelint-config-standard-scss": "^15.0.1",
|
|
123
|
+
"typescript": "~5.8.3",
|
|
124
|
+
"typescript-eslint": "8.32.1"
|
|
130
125
|
}
|
|
131
126
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { GeneratorSchemaBase } from '../../types';
|
|
2
2
|
|
|
3
|
-
export type ComponentType = 'avatar' | 'button' | 'checkbox' | 'input' | 'switch' | 'textarea';
|
|
3
|
+
export type ComponentType = 'avatar' | 'button' | 'checkbox' | 'divider' | 'input' | 'switch' | 'textarea';
|
|
4
4
|
|
|
5
5
|
export interface ComponentGeneratorSchema extends GeneratorSchemaBase {
|
|
6
6
|
components: ComponentType[];
|
|
@@ -2,9 +2,9 @@ $bg-color-hover: #333;
|
|
|
2
2
|
$bg-color: #000;
|
|
3
3
|
$color: #fff;
|
|
4
4
|
$padding: 8px 24px;
|
|
5
|
-
$shadow-hover: 0 0 0 3px rgb(0 123 255 / 50%);
|
|
6
5
|
$shadow: 0 2px 4px rgb(0 0 0 / 10%);
|
|
7
6
|
$transition-duration: 0.4s;
|
|
7
|
+
$outline: var(--zen-outline, 2px solid hsl(200deg 100 50 / 50%));
|
|
8
8
|
|
|
9
9
|
:host {
|
|
10
10
|
display: inline-block;
|
|
@@ -15,12 +15,13 @@ $transition-duration: 0.4s;
|
|
|
15
15
|
border: none;
|
|
16
16
|
padding: $padding;
|
|
17
17
|
border-radius: 99999px;
|
|
18
|
-
transition:
|
|
18
|
+
transition-property: background-color, opacity;
|
|
19
|
+
transition-duration: $transition-duration;
|
|
20
|
+
transition-timing-function: ease;
|
|
19
21
|
background-color: $bg-color;
|
|
20
22
|
color: $color;
|
|
21
23
|
box-shadow: $shadow;
|
|
22
24
|
text-decoration: none;
|
|
23
|
-
outline: none;
|
|
24
25
|
overflow: hidden;
|
|
25
26
|
position: relative;
|
|
26
27
|
}
|
|
@@ -31,8 +32,8 @@ $transition-duration: 0.4s;
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/* Focus state */
|
|
34
|
-
:host:focus {
|
|
35
|
-
|
|
35
|
+
:host:focus-visible {
|
|
36
|
+
outline: $outline;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
/* Disabled state */
|
|
@@ -8,7 +8,7 @@ $appearance: var(--zen-checkbox-appearance, hsl(0% 0% 10%));
|
|
|
8
8
|
$disabled-opacity: var(--zen-checkbox-disabled-opacity, 0.6);
|
|
9
9
|
$border: var(--zen-checkbox-border, 1px solid hsl(0% 0% 80%));
|
|
10
10
|
$error: var(--zen-error, hsl(0% 70% 50%));
|
|
11
|
-
$outline: var(--zen-outline,
|
|
11
|
+
$outline: var(--zen-outline, 2px solid hsl(200deg 100 50 / 50%));
|
|
12
12
|
|
|
13
13
|
// Animations
|
|
14
14
|
$transition-duration: var(--zen-transition-duration, 0.2s);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
2
1
|
import { booleanAttribute, ChangeDetectionStrategy, Component, forwardRef, input, model } from '@angular/core';
|
|
2
|
+
import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* ZenCheckboxComponent is a reusable checkbox component designed to provide
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
$appearance: var(--zen-divider-appearance, hsl(0% 0% 10%));
|
|
2
|
+
$type: var(--zen-divider-type, solid);
|
|
3
|
+
$align-offset: var(--zen-divider-align-offset, 25%);
|
|
4
|
+
$gap: var(--zen-divider-gap, 0.25rem);
|
|
5
|
+
$thickness: var(--zen-divider-thickness, 1px);
|
|
6
|
+
|
|
7
|
+
:host {
|
|
8
|
+
width: 100%;
|
|
9
|
+
display: flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
gap: $gap;
|
|
12
|
+
|
|
13
|
+
&::before,
|
|
14
|
+
&::after {
|
|
15
|
+
content: '';
|
|
16
|
+
display: block;
|
|
17
|
+
width: 100%;
|
|
18
|
+
height: 0;
|
|
19
|
+
border-color: $appearance;
|
|
20
|
+
border-style: $type;
|
|
21
|
+
border-width: #{$thickness} 0 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&:not(.has-content)::after {
|
|
25
|
+
content: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&.zen-align-start::before,
|
|
29
|
+
&.zen-align-end::after {
|
|
30
|
+
width: $align-offset;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:host[vertical]:not([vertical='false']) {
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
width: unset;
|
|
37
|
+
height: 100%;
|
|
38
|
+
|
|
39
|
+
&::before,
|
|
40
|
+
&::after {
|
|
41
|
+
content: '';
|
|
42
|
+
display: block;
|
|
43
|
+
width: unset;
|
|
44
|
+
height: 100%;
|
|
45
|
+
border-width: 0 #{$thickness} 0 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&.zen-align-start::before,
|
|
49
|
+
&.zen-align-end::after {
|
|
50
|
+
height: $align-offset;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { ZenDividerComponent } from './divider.component';
|
|
4
|
+
|
|
5
|
+
describe('DividerComponent', () => {
|
|
6
|
+
let component: ZenDividerComponent;
|
|
7
|
+
let fixture: ComponentFixture<ZenDividerComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
imports: [ZenDividerComponent],
|
|
12
|
+
}).compileComponents();
|
|
13
|
+
|
|
14
|
+
fixture = TestBed.createComponent(ZenDividerComponent);
|
|
15
|
+
component = fixture.componentInstance;
|
|
16
|
+
fixture.detectChanges();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should create', () => {
|
|
20
|
+
expect(component).toBeTruthy();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, computed, ElementRef, inject, input } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ZenDividerComponent is a reusable divider component that provides a simple way to
|
|
5
|
+
* separate content sections visually. It supports both horizontal (default) and vertical
|
|
6
|
+
* orientations and can contain optional content.
|
|
7
|
+
*
|
|
8
|
+
* The divider automatically detects if it contains content and applies appropriate styling.
|
|
9
|
+
* Content alignment can be controlled via the `align` input property.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```html
|
|
13
|
+
* <zen-divider/>
|
|
14
|
+
* <zen-divider>With content</zen-divider>
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ### CSS Custom Properties
|
|
18
|
+
* You can customize the component using CSS custom properties:
|
|
19
|
+
*
|
|
20
|
+
* ```css
|
|
21
|
+
* :root {
|
|
22
|
+
* --zen-divider-appearance: red;
|
|
23
|
+
* --zen-divider-type: dotted;
|
|
24
|
+
* --zen-divider-align-offset: 10%;
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @author Konrad Stępień
|
|
29
|
+
* @license {@link https://github.com/kstepien3/ng-zen/blob/master/LICENSE|BSD-2-Clause}
|
|
30
|
+
* @see [GitHub](https://github.com/kstepien3/ng-zen)
|
|
31
|
+
*/
|
|
32
|
+
@Component({
|
|
33
|
+
selector: `zen-divider, zen-divider[vertical],`,
|
|
34
|
+
template: '<ng-content/>',
|
|
35
|
+
styleUrl: './divider.component.scss',
|
|
36
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
37
|
+
host: {
|
|
38
|
+
'[class.has-content]': 'hasContent()',
|
|
39
|
+
'[class]': '"zen-align-"+align()',
|
|
40
|
+
},
|
|
41
|
+
})
|
|
42
|
+
export class ZenDividerComponent {
|
|
43
|
+
/**
|
|
44
|
+
* Controls the alignment of content within the divider.
|
|
45
|
+
* @default 'center'
|
|
46
|
+
*/
|
|
47
|
+
readonly align = input<'start' | 'end' | 'center'>('center');
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Computed property that determines if the divider contains any content.
|
|
51
|
+
* Used to apply appropriate styling when content is present.
|
|
52
|
+
*/
|
|
53
|
+
readonly hasContent = computed(() => {
|
|
54
|
+
return this.elementRef.nativeElement.childNodes.length > 0;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
private readonly elementRef = inject(ElementRef);
|
|
58
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/angular';
|
|
2
|
+
|
|
3
|
+
import { ZenDividerComponent } from './divider.component';
|
|
4
|
+
|
|
5
|
+
interface StoryParams {
|
|
6
|
+
content: string;
|
|
7
|
+
vertical: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
title: 'Components/Divider',
|
|
12
|
+
component: ZenDividerComponent,
|
|
13
|
+
tags: ['autodocs'],
|
|
14
|
+
parameters: {
|
|
15
|
+
layout: 'padded',
|
|
16
|
+
},
|
|
17
|
+
argTypes: {
|
|
18
|
+
content: { control: 'text' },
|
|
19
|
+
vertical: { control: 'boolean' },
|
|
20
|
+
align: { control: 'select', options: ['start', 'center', 'end'] },
|
|
21
|
+
},
|
|
22
|
+
args: { content: '', vertical: false, align: 'center' },
|
|
23
|
+
} satisfies Meta<ZenDividerComponent & StoryParams>;
|
|
24
|
+
|
|
25
|
+
type Story = StoryObj<ZenDividerComponent & StoryParams>;
|
|
26
|
+
|
|
27
|
+
export const Default: Story = {
|
|
28
|
+
render: args => ({
|
|
29
|
+
props: { ...args },
|
|
30
|
+
template: `
|
|
31
|
+
<div style="height: 200px">
|
|
32
|
+
<zen-divider [align]="'${args.align}'" [attr.vertical]="${args.vertical}">
|
|
33
|
+
${args.content ?? ''}
|
|
34
|
+
</zen-divider>
|
|
35
|
+
</div>`,
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const Vertical: Story = {
|
|
40
|
+
render: args => ({
|
|
41
|
+
props: { ...args },
|
|
42
|
+
template: `
|
|
43
|
+
<div style="height: 200px; display: flex; justify-content: space-between">
|
|
44
|
+
<zen-divider vertical align="start">
|
|
45
|
+
START
|
|
46
|
+
</zen-divider>
|
|
47
|
+
<zen-divider vertical>
|
|
48
|
+
CENTER
|
|
49
|
+
</zen-divider>
|
|
50
|
+
<zen-divider vertical align="end">
|
|
51
|
+
END
|
|
52
|
+
</zen-divider>
|
|
53
|
+
</div>`,
|
|
54
|
+
}),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const Customization: Story = {
|
|
58
|
+
render: () => ({
|
|
59
|
+
template: `
|
|
60
|
+
<div style="display: flex; flex-direction: column; gap: 1rem">
|
|
61
|
+
<zen-divider style="--zen-divider-appearance: red;">appearance</zen-divider>
|
|
62
|
+
<zen-divider style="--zen-divider-type: dotted;">type</zen-divider>
|
|
63
|
+
<zen-divider style="--zen-divider-align-offset: 10%;" align="start">offset</zen-divider>
|
|
64
|
+
<zen-divider style="--zen-divider-gap: 50px">gap</zen-divider>
|
|
65
|
+
<zen-divider style="--zen-divider-thickness: 8px">offset</zen-divider>
|
|
66
|
+
</div>
|
|
67
|
+
`,
|
|
68
|
+
}),
|
|
69
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './divider.component';
|
|
@@ -6,7 +6,7 @@ $focus-shadow: var(--zen-input-focus-shadow, 0 1px 4px hsla(0% 0% 60% / 20%) ins
|
|
|
6
6
|
$placeholder-color: var(--zen-input-placeholder-color, hsl(0% 0% 60%));
|
|
7
7
|
|
|
8
8
|
// Color Palette
|
|
9
|
-
$outline: var(--zen-outline,
|
|
9
|
+
$outline: var(--zen-outline, 2px solid hsl(200deg 100 50 / 50%));
|
|
10
10
|
$error: var(--zen-error, hsl(0% 70% 50%));
|
|
11
11
|
|
|
12
12
|
input {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
$outline: var(--zen-outline, 2px solid hsl(
|
|
1
|
+
$outline: var(--zen-outline, 2px solid hsl(200deg 100 50 / 50%));
|
|
2
2
|
$transition-duration: 0.15s;
|
|
3
3
|
$placeholder-color: var(--zen-input-placeholder-color, hsl(0% 0% 60%));
|
|
4
4
|
$size: var(--zen-switch-size, 16px);
|
|
@@ -43,7 +43,7 @@ $height: calc(#{$size} + #{$margin} * 2);
|
|
|
43
43
|
width: calc(#{$size} + 2px);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
&:focus {
|
|
46
|
+
&:focus-visible {
|
|
47
47
|
outline: $outline;
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -6,7 +6,7 @@ $focus-shadow: var(--zen-input-focus-shadow, 0 1px 4px hsla(0% 0% 60% / 20%) ins
|
|
|
6
6
|
$placeholder-color: var(--zen-input-placeholder-color, hsl(0% 0% 60%));
|
|
7
7
|
|
|
8
8
|
// Color Palette
|
|
9
|
-
$outline: var(--zen-outline,
|
|
9
|
+
$outline: var(--zen-outline, 2px solid hsl(200deg 100 50 / 50%));
|
|
10
10
|
$error: var(--zen-error, hsl(0% 70% 50%));
|
|
11
11
|
|
|
12
12
|
:host {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"type": "array",
|
|
11
11
|
"items": {
|
|
12
12
|
"type": "string",
|
|
13
|
-
"enum": ["avatar", "button", "checkbox", "input", "switch", "textarea"]
|
|
13
|
+
"enum": ["avatar", "button", "checkbox", "divider", "input", "switch", "textarea"]
|
|
14
14
|
},
|
|
15
15
|
"multiselect": true,
|
|
16
16
|
"x-prompt": "Which component should be generated?"
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
|
|
1
|
+
import { chain, Rule, schematic, SchematicContext, Tree } from '@angular-devkit/schematics';
|
|
2
2
|
|
|
3
|
-
import { addPathToTsconfigUtil } from '../../utils';
|
|
4
3
|
import { NgZenGeneratorSchema } from './ng-zen-generator';
|
|
5
4
|
|
|
6
5
|
export function ngAdd(options: NgZenGeneratorSchema): Rule {
|
|
7
|
-
return (
|
|
6
|
+
return (_tree: Tree, _context: SchematicContext) => {
|
|
8
7
|
_context.logger.info('Adding library to the project');
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return tree;
|
|
9
|
+
// Run other schematics from ng-add
|
|
10
|
+
return chain([schematic('component', options)]);
|
|
13
11
|
};
|
|
14
12
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { GeneratorSchemaBase } from '../../types';
|
|
2
|
+
|
|
3
|
+
export type NgZenGeneratorSchema = GeneratorSchemaBase;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalize, strings } from '@angular-devkit/core';
|
|
2
2
|
import { apply, applyTemplates, chain, filter, mergeWith, move, Rule, url } from '@angular-devkit/schematics';
|
|
3
|
+
|
|
3
4
|
import { GeneratorSchemaBase } from '../types';
|
|
4
5
|
import { SchematicsFolder } from '../types/schematics-folder.type';
|
|
5
6
|
|
package/src/utils/index.ts
CHANGED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { createBuilder } from '@angular-devkit/architect';
|
|
2
|
-
import { execa } from 'execa';
|
|
3
|
-
import cpy from 'cpy';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import fs from 'fs-extra';
|
|
6
|
-
|
|
7
|
-
const LOG = {
|
|
8
|
-
log: (logger, level, type, message) => {
|
|
9
|
-
const timestamp = new Date().toISOString();
|
|
10
|
-
const output = `[${timestamp}] [${type}] ${message}`;
|
|
11
|
-
|
|
12
|
-
// Use the appropriate logger method based on the log level
|
|
13
|
-
switch (level) {
|
|
14
|
-
case 'INFO':
|
|
15
|
-
logger.info(output);
|
|
16
|
-
break;
|
|
17
|
-
case 'ERROR':
|
|
18
|
-
logger.error(output);
|
|
19
|
-
break;
|
|
20
|
-
default:
|
|
21
|
-
logger.log(output);
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
info: (logger, type, message) => LOG.log(logger, 'INFO', type, message),
|
|
26
|
-
error: (logger, type, message) => LOG.log(logger, 'ERROR', type, message),
|
|
27
|
-
};
|
|
28
|
-
async function cleanOutputDirectory(outputDir, context) {
|
|
29
|
-
try {
|
|
30
|
-
if (await fs.pathExists(outputDir)) {
|
|
31
|
-
await fs.rm(outputDir, { recursive: true, force: true });
|
|
32
|
-
}
|
|
33
|
-
await fs.mkdir(outputDir, { recursive: true });
|
|
34
|
-
} catch (error) {
|
|
35
|
-
LOG.error(context.logger, 'ERROR', `Failed to clean output directory: ${error.message}`);
|
|
36
|
-
context.logger.error();
|
|
37
|
-
throw error;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async function getOutputDir(tsConfigPath, workspaceRoot) {
|
|
42
|
-
const fullPath = path.resolve(workspaceRoot, tsConfigPath);
|
|
43
|
-
const configContent = await fs.readFile(fullPath, 'utf-8');
|
|
44
|
-
const config = JSON.parse(configContent);
|
|
45
|
-
|
|
46
|
-
const outDir = config.compilerOptions?.outDir || 'dist';
|
|
47
|
-
const tsConfigDir = path.dirname(fullPath);
|
|
48
|
-
|
|
49
|
-
return path.resolve(tsConfigDir, outDir);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async function compileTypeScript(tsConfig, context) {
|
|
53
|
-
await execa('tsc', ['-p', tsConfig], {
|
|
54
|
-
stdio: 'inherit',
|
|
55
|
-
cwd: context.currentDirectory,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async function copyProjectFiles(files, outputDir, context) {
|
|
60
|
-
await cpy(files, outputDir, {
|
|
61
|
-
parents: true,
|
|
62
|
-
cwd: context.currentDirectory,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async function cleanPackageJson(outputDir) {
|
|
67
|
-
const distPackageJson = path.join(outputDir, 'package.json');
|
|
68
|
-
const pkg = await fs.readJson(distPackageJson);
|
|
69
|
-
delete pkg.scripts;
|
|
70
|
-
delete pkg.devDependencies;
|
|
71
|
-
await fs.writeJson(distPackageJson, pkg, { spaces: 2 });
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export default createBuilder(async (options, context) => {
|
|
75
|
-
try {
|
|
76
|
-
const outputDir = await getOutputDir(options.tsConfig, context.workspaceRoot);
|
|
77
|
-
LOG.info(context.logger, 'BUILD', 'Starting build process...');
|
|
78
|
-
|
|
79
|
-
LOG.info(context.logger, 'CLEANING', `Cleaning old distribution files in ${outputDir}`);
|
|
80
|
-
await cleanOutputDirectory(outputDir, context);
|
|
81
|
-
LOG.info(context.logger, 'CLEANING', `Cleaning completed successfully.`);
|
|
82
|
-
|
|
83
|
-
LOG.info(context.logger, 'COMPILING', `Compiling TypeScript files using config: ${options.tsConfig}`);
|
|
84
|
-
await compileTypeScript(options.tsConfig, context);
|
|
85
|
-
LOG.info(context.logger, 'COMPILING', 'Compilation completed successfully.');
|
|
86
|
-
|
|
87
|
-
LOG.info(context.logger, 'COPYING', `Copying project files to: ${outputDir}`);
|
|
88
|
-
await copyProjectFiles(options.files, outputDir, context);
|
|
89
|
-
LOG.info(context.logger, 'COPYING', 'Copy completed successfully.');
|
|
90
|
-
|
|
91
|
-
LOG.info(context.logger, 'UPDATING', `Updating package.json file.`);
|
|
92
|
-
await cleanPackageJson(outputDir);
|
|
93
|
-
LOG.info(context.logger, 'UPDATING', 'Update completed successfully.');
|
|
94
|
-
|
|
95
|
-
return { success: true };
|
|
96
|
-
} catch (error) {
|
|
97
|
-
LOG.error(context.logger, 'ERROR', `Build failed: ${error.message}`);
|
|
98
|
-
return { success: false };
|
|
99
|
-
}
|
|
100
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "http://json-schema.org/schema",
|
|
3
|
-
"type": "object",
|
|
4
|
-
"properties": {
|
|
5
|
-
"files": {
|
|
6
|
-
"type": "array",
|
|
7
|
-
"items": {
|
|
8
|
-
"type": "string"
|
|
9
|
-
}
|
|
10
|
-
},
|
|
11
|
-
"outputDir": {
|
|
12
|
-
"type": "string"
|
|
13
|
-
},
|
|
14
|
-
"tsConfig": {
|
|
15
|
-
"type": "string"
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { SchematicsException, Tree } from '@angular-devkit/schematics';
|
|
2
|
-
|
|
3
|
-
export function addPathToTsconfigUtil(tree: Tree, key: string, value: string[]): void {
|
|
4
|
-
const tsconfigPath = 'tsconfig.json';
|
|
5
|
-
|
|
6
|
-
// Check if tsconfig.json exists
|
|
7
|
-
if (!tree.exists(tsconfigPath)) {
|
|
8
|
-
throw new SchematicsException('tsconfig.json does not exist');
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// Read tsconfig.json content as string
|
|
12
|
-
const tsconfigBuffer = tree.read(tsconfigPath);
|
|
13
|
-
if (!tsconfigBuffer) {
|
|
14
|
-
throw new SchematicsException('Failed to read tsconfig.json');
|
|
15
|
-
}
|
|
16
|
-
let tsconfigContent = tsconfigBuffer.toString('utf-8');
|
|
17
|
-
|
|
18
|
-
// Extract and preserve the comment
|
|
19
|
-
const commentMatch = tsconfigContent.match(/\/\*[\s\S]*?\*\//);
|
|
20
|
-
const comment = commentMatch ? commentMatch[0] : '';
|
|
21
|
-
|
|
22
|
-
// Remove comment from content to parse JSON
|
|
23
|
-
tsconfigContent = tsconfigContent.replace(comment, '');
|
|
24
|
-
|
|
25
|
-
// Parse tsconfig.json content
|
|
26
|
-
let tsconfig;
|
|
27
|
-
try {
|
|
28
|
-
tsconfig = JSON.parse(tsconfigContent);
|
|
29
|
-
} catch (e) {
|
|
30
|
-
throw new SchematicsException('Failed to parse tsconfig.json' + e);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Modify compilerOptions.paths to add your new mapping
|
|
34
|
-
if (!tsconfig.compilerOptions) {
|
|
35
|
-
tsconfig.compilerOptions = {};
|
|
36
|
-
}
|
|
37
|
-
if (!tsconfig.compilerOptions.paths) {
|
|
38
|
-
tsconfig.compilerOptions.paths = {};
|
|
39
|
-
}
|
|
40
|
-
tsconfig.compilerOptions.paths[key] = value;
|
|
41
|
-
|
|
42
|
-
// Convert tsconfig back to JSON string
|
|
43
|
-
tsconfigContent = JSON.stringify(tsconfig, null, 2);
|
|
44
|
-
|
|
45
|
-
// Ensure the preserved comment is prepended to the JSON string
|
|
46
|
-
tsconfigContent = `${comment}\n${tsconfigContent}`;
|
|
47
|
-
|
|
48
|
-
// Write back to tsconfig.json
|
|
49
|
-
tree.overwrite(tsconfigPath, tsconfigContent);
|
|
50
|
-
}
|