@ng-zen/cli 0.0.1-alpha.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/CHANGELOG.md +28 -0
- package/LICENSE +24 -0
- package/README.md +39 -0
- package/package.json +38 -0
- package/schematics/collection.json +16 -0
- package/schematics/components/components-generator.d.ts +5 -0
- package/schematics/components/components-generator.d.ts.map +1 -0
- package/schematics/components/components-generator.js +3 -0
- package/schematics/components/components-generator.js.map +1 -0
- package/schematics/components/files/avatar/avatar.component.scss +23 -0
- package/schematics/components/files/avatar/avatar.component.spec.ts +22 -0
- package/schematics/components/files/avatar/avatar.component.ts +60 -0
- package/schematics/components/files/avatar/index.ts +1 -0
- package/schematics/components/files/badge/badge.component.scss +70 -0
- package/schematics/components/files/badge/badge.component.spec.ts +22 -0
- package/schematics/components/files/badge/badge.component.ts +52 -0
- package/schematics/components/files/badge/index.ts +1 -0
- package/schematics/components/files/button/button.component.scss +42 -0
- package/schematics/components/files/button/button.component.spec.ts +22 -0
- package/schematics/components/files/button/button.component.ts +11 -0
- package/schematics/components/files/button/index.ts +10 -0
- package/schematics/components/files/pin/index.ts +1 -0
- package/schematics/components/files/pin/pin.component.scss +29 -0
- package/schematics/components/files/pin/pin.component.spec.ts +22 -0
- package/schematics/components/files/pin/pin.component.ts +46 -0
- package/schematics/components/files/switch/index.ts +10 -0
- package/schematics/components/files/switch/zen-switch.component.html +11 -0
- package/schematics/components/files/switch/zen-switch.component.scss +62 -0
- package/schematics/components/files/switch/zen-switch.component.spec.ts +22 -0
- package/schematics/components/files/switch/zen-switch.component.ts +123 -0
- package/schematics/components/files/tag/index.ts +10 -0
- package/schematics/components/files/tag/tag.component.scss +9 -0
- package/schematics/components/files/tag/tag.component.spec.ts +22 -0
- package/schematics/components/files/tag/tag.component.ts +26 -0
- package/schematics/components/index.d.ts +4 -0
- package/schematics/components/index.d.ts.map +1 -0
- package/schematics/components/index.js +21 -0
- package/schematics/components/index.js.map +1 -0
- package/schematics/components/schema.json +25 -0
- package/schematics/components/templates/README.md.template +41 -0
- package/schematics/ng-add/index.d.ts +4 -0
- package/schematics/ng-add/index.d.ts.map +1 -0
- package/schematics/ng-add/index.js +13 -0
- package/schematics/ng-add/index.js.map +1 -0
- package/schematics/ng-add/ng-zen-generator.d.ts +4 -0
- package/schematics/ng-add/ng-zen-generator.d.ts.map +1 -0
- package/schematics/ng-add/ng-zen-generator.js +3 -0
- package/schematics/ng-add/ng-zen-generator.js.map +1 -0
- package/schematics/ng-add/schema.json +15 -0
- package/schematics/utils/add-path-to-tsconfig.util.d.ts +3 -0
- package/schematics/utils/add-path-to-tsconfig.util.d.ts.map +1 -0
- package/schematics/utils/add-path-to-tsconfig.util.js +46 -0
- package/schematics/utils/add-path-to-tsconfig.util.js.map +1 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### 0.0.1-alpha.1 (2024-06-26)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* add BSD 2-Clause License and author information ([#52](https://github.com/Kordrad/ng-zen/issues/52)) ([9336578](https://github.com/Kordrad/ng-zen/commit/93365782656f8166f6f8205dc9c4ea9f4c8c0c27))
|
|
10
|
+
* add docs script ([#39](https://github.com/Kordrad/ng-zen/issues/39)) ([d5e1e37](https://github.com/Kordrad/ng-zen/commit/d5e1e37eed26ebf2227c9039ad9b97161f7316c3))
|
|
11
|
+
* **avatar:** add component ([#32](https://github.com/Kordrad/ng-zen/issues/32)) ([35d89ab](https://github.com/Kordrad/ng-zen/commit/35d89abeb5baf934ec68b83ca8ef5f28ff40332c))
|
|
12
|
+
* **badge:** add new component ([#10](https://github.com/Kordrad/ng-zen/issues/10)) ([06b7e3a](https://github.com/Kordrad/ng-zen/commit/06b7e3acf4d947ee8ee79bde772d987d813bbf62))
|
|
13
|
+
* **badge:** add top/right/bottom/left positions to component ([#20](https://github.com/Kordrad/ng-zen/issues/20)) ([4cb3b6e](https://github.com/Kordrad/ng-zen/commit/4cb3b6e5db1f9e239ccee01c86a7b00102cfb70e))
|
|
14
|
+
* **button:** add component ([#59](https://github.com/Kordrad/ng-zen/issues/59)) ([b72a67a](https://github.com/Kordrad/ng-zen/commit/b72a67aa39ba3dd9a893395d178935573cfc9038))
|
|
15
|
+
* **kit:** add new library ([#7](https://github.com/Kordrad/ng-zen/issues/7)) ([1576da6](https://github.com/Kordrad/ng-zen/commit/1576da623fece9910e289d53abe0928d8c15664b))
|
|
16
|
+
* **pin:** add component ([#33](https://github.com/Kordrad/ng-zen/issues/33)) ([2f8c021](https://github.com/Kordrad/ng-zen/commit/2f8c0214a47defb0f748e399b83872ef9e8cc2a0))
|
|
17
|
+
* **pin:** add stream animation ([#34](https://github.com/Kordrad/ng-zen/issues/34)) ([1fc4968](https://github.com/Kordrad/ng-zen/commit/1fc4968e31ce05fe36cfb1b89d9248df68684a2f))
|
|
18
|
+
* **pull-request-check:** cache module installation to improve performance ([#53](https://github.com/Kordrad/ng-zen/issues/53)) ([c82c279](https://github.com/Kordrad/ng-zen/commit/c82c2792c8b0b436e5856a63a53c5b2ffd433a76))
|
|
19
|
+
* **schematics:** add new project ([#45](https://github.com/Kordrad/ng-zen/issues/45)) ([1325318](https://github.com/Kordrad/ng-zen/commit/1325318a8c4941f3ff696138d7ae427aa95279f1))
|
|
20
|
+
* **storybook:** add storybook instead of demo app ([#26](https://github.com/Kordrad/ng-zen/issues/26)) ([edac7b1](https://github.com/Kordrad/ng-zen/commit/edac7b16cb2573c86b52a614b2539e9fb6b9fafe))
|
|
21
|
+
* **switch:** add component ([#56](https://github.com/Kordrad/ng-zen/issues/56)) ([a6028d5](https://github.com/Kordrad/ng-zen/commit/a6028d5d3bc00fd5f13bf51192225e2eda68e0fc))
|
|
22
|
+
* **tag:** add component ([#35](https://github.com/Kordrad/ng-zen/issues/35)) ([33dc67c](https://github.com/Kordrad/ng-zen/commit/33dc67c5830ed42323e76c8658ea1d85c0509155))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* **eslint:** remove quiet flag ([#21](https://github.com/Kordrad/ng-zen/issues/21)) ([06fbc75](https://github.com/Kordrad/ng-zen/commit/06fbc752b50470fec745bcd77d4b64ba2bec82ee))
|
|
28
|
+
* restore project name to ng-zen ([#19](https://github.com/Kordrad/ng-zen/issues/19)) ([0c659d7](https://github.com/Kordrad/ng-zen/commit/0c659d77bbda95414fd29ab2dbc58b4ffd3d61d7))
|
package/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
BSD 2-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, Konrad Stępień
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
16
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
17
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
19
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
20
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
21
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
22
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
23
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
24
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @ng-zen/cli
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The ng-zen CLI is a command-line tool designed to facilitate the generation of UI-kit elements for Angular applications using Angular schematics. It provides out-of-the-box components that can be quickly integrated into Angular projects.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
To install ng-zen CLI, use the following command:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
ng add @ng-zen/cli
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This command will add the necessary dependencies and configurations to your Angular project.
|
|
16
|
+
|
|
17
|
+
## Generating Components
|
|
18
|
+
|
|
19
|
+
You can generate components using the ng-zen CLI. Components are generated using the following command format:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
ng generate @ng-zen/cli:component
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## License
|
|
26
|
+
|
|
27
|
+
This project is licensed under the BSD 2-Clause License. For more details, refer to the LICENSE file in the repository.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## Author
|
|
31
|
+
|
|
32
|
+
**@ng-zen/cli** is maintained by Konrad Stępień.
|
|
33
|
+
|
|
34
|
+
- Email: kord.stp@gmail.com
|
|
35
|
+
- LinkedIn: [Konrad Stępień](https://www.linkedin.com/in/konradstepien/)
|
|
36
|
+
|
|
37
|
+
## Documentation
|
|
38
|
+
|
|
39
|
+
The ng-zen CLI is documented using Storybook for component examples and JSDoc, as well as Compodoc for Angular project documentation.
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ng-zen/cli",
|
|
3
|
+
"version": "0.0.1-alpha.1",
|
|
4
|
+
"license": "BSD-2-Clause",
|
|
5
|
+
"private": false,
|
|
6
|
+
"repository": {
|
|
7
|
+
"url": "https://github.com/Kordrad/ng-zen",
|
|
8
|
+
"directory": "projects/cli"
|
|
9
|
+
},
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/Kordrad/ng-zen/issues"
|
|
12
|
+
},
|
|
13
|
+
"author": {
|
|
14
|
+
"name": "Konrad Stępień",
|
|
15
|
+
"email": "kord.stp@gmail.com",
|
|
16
|
+
"url": "https://www.linkedin.com/in/KonradStepien/"
|
|
17
|
+
},
|
|
18
|
+
"schematics": "./schematics/collection.json",
|
|
19
|
+
"ng-add": {
|
|
20
|
+
"save": "devDependencies"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"@angular/common": "^17.3.0",
|
|
24
|
+
"@angular/core": "^17.3.0"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@angular-devkit/core": "^17.3.0",
|
|
28
|
+
"@angular-devkit/schematics": "^17.3.0",
|
|
29
|
+
"tslib": "^2.3.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@chromatic-com/storybook": "^1.3.5",
|
|
33
|
+
"@storybook/addon-essentials": "^8.1.0",
|
|
34
|
+
"@storybook/addon-interactions": "^8.1.0",
|
|
35
|
+
"@storybook/addon-links": "^8.1.0"
|
|
36
|
+
},
|
|
37
|
+
"sideEffects": false
|
|
38
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../node_modules/@angular-devkit/schematics/collection-schema.json",
|
|
3
|
+
"schematics": {
|
|
4
|
+
"ng-add": {
|
|
5
|
+
"description": "Add library to the project.",
|
|
6
|
+
"factory": "./ng-add/index#ngAdd",
|
|
7
|
+
"schema": "./ng-add/schema.json"
|
|
8
|
+
},
|
|
9
|
+
"component": {
|
|
10
|
+
"description": "This schematic generates ui components",
|
|
11
|
+
"factory": "./components/index#componentGenerator",
|
|
12
|
+
"schema": "./components/schema.json",
|
|
13
|
+
"aliases": ["c"]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components-generator.d.ts","sourceRoot":"","sources":["../../../../../projects/cli/schematics/components/components-generator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,CAAC,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,KAAK,CAAC,EAAE,CAAC;IACzE,IAAI,EAAE,MAAM,CAAC;CACd"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components-generator.js","sourceRoot":"","sources":["../../../../../projects/cli/schematics/components/components-generator.ts"],"names":[],"mappings":"","sourcesContent":["export interface ComponentGeneratorSchema {\r\n components: ('avatar' | 'badge' | 'button' | 'pin' | 'switch' | 'tag')[];\r\n path: string;\r\n}\r\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
zen-avatar {
|
|
2
|
+
height: 32px;
|
|
3
|
+
width: 32px;
|
|
4
|
+
position: relative;
|
|
5
|
+
display: flex;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
align-items: center;
|
|
8
|
+
border-radius: 50%;
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
touch-action: none;
|
|
11
|
+
pointer-events: none;
|
|
12
|
+
user-select: none;
|
|
13
|
+
|
|
14
|
+
// Text
|
|
15
|
+
&:not(:has(img)) {
|
|
16
|
+
background-color: #6b7280;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
& > * {
|
|
20
|
+
height: 100%;
|
|
21
|
+
width: 100%;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { ZenAvatarComponent } from './avatar.component';
|
|
4
|
+
|
|
5
|
+
describe('ZenAvatarComponent', () => {
|
|
6
|
+
let component: ZenAvatarComponent;
|
|
7
|
+
let fixture: ComponentFixture<ZenAvatarComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
imports: [ZenAvatarComponent],
|
|
12
|
+
}).compileComponents();
|
|
13
|
+
|
|
14
|
+
fixture = TestBed.createComponent(ZenAvatarComponent);
|
|
15
|
+
component = fixture.componentInstance;
|
|
16
|
+
fixture.detectChanges();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should create', () => {
|
|
20
|
+
expect(component).toBeTruthy();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { NgOptimizedImage } from '@angular/common';
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
input,
|
|
6
|
+
ViewEncapsulation,
|
|
7
|
+
} from '@angular/core';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A component to display an avatar image. If a valid image source URL is provided,
|
|
11
|
+
* it will render an image element. Otherwise, it will display projected content.
|
|
12
|
+
*
|
|
13
|
+
* The component uses Angular's optimized image directives for enhanced performance.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
*
|
|
17
|
+
* ```html
|
|
18
|
+
* <!-- If an image source is provided, it will display the image -->
|
|
19
|
+
* <zen-avatar [src]="'/path/to/image.jpg'" />
|
|
20
|
+
*
|
|
21
|
+
* <!-- If no image source is provided, it will display the projected content -->
|
|
22
|
+
* <zen-avatar> A </zen-avatar>
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* <zen-avatar src="https://picsum.photos/32" />
|
|
27
|
+
*
|
|
28
|
+
* @component
|
|
29
|
+
* @selector `zen-avatar`
|
|
30
|
+
*
|
|
31
|
+
* @license BSD-2-Clause
|
|
32
|
+
* @author Konrad Stępień <kord.stp@gmail.com>
|
|
33
|
+
* @link https://github.com/Kordrad/ng-zen
|
|
34
|
+
*/
|
|
35
|
+
@Component({
|
|
36
|
+
selector: 'zen-avatar',
|
|
37
|
+
standalone: true,
|
|
38
|
+
imports: [NgOptimizedImage],
|
|
39
|
+
template: `
|
|
40
|
+
@if (src()) {
|
|
41
|
+
<img [ngSrc]="src()" alt="" fill />
|
|
42
|
+
} @else {
|
|
43
|
+
<ng-content />
|
|
44
|
+
}
|
|
45
|
+
`,
|
|
46
|
+
styleUrl: './avatar.component.scss',
|
|
47
|
+
encapsulation: ViewEncapsulation.None,
|
|
48
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
49
|
+
})
|
|
50
|
+
export class ZenAvatarComponent {
|
|
51
|
+
/**
|
|
52
|
+
* Path to the image source. If the `src` is provided, an image element will be rendered.
|
|
53
|
+
* Otherwise, the content projected into this component will be displayed.
|
|
54
|
+
*
|
|
55
|
+
* @default ''
|
|
56
|
+
* @input
|
|
57
|
+
* @type string
|
|
58
|
+
*/
|
|
59
|
+
readonly src = input<string>('');
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './avatar.component';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--zen-badge-offset: unset;
|
|
3
|
+
--zen-badge-offset-x: unset;
|
|
4
|
+
--zen-badge-offset-y: unset;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
zen-badge,
|
|
8
|
+
[zenBadge] {
|
|
9
|
+
display: inline-flex;
|
|
10
|
+
position: relative;
|
|
11
|
+
|
|
12
|
+
[topLeft],
|
|
13
|
+
[top],
|
|
14
|
+
[topRight],
|
|
15
|
+
[right],
|
|
16
|
+
[bottomRight],
|
|
17
|
+
[bottom],
|
|
18
|
+
[bottomLeft],
|
|
19
|
+
[left] {
|
|
20
|
+
position: absolute;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
[topLeft] {
|
|
24
|
+
top: var(--zen-badge-offset-y, calc(var(--zen-badge-offset, 0px) * -1));
|
|
25
|
+
left: var(--zen-badge-offset-x, calc(var(--zen-badge-offset, 0px) * -1));
|
|
26
|
+
transform: translateY(-50%) translateX(-50%);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
[top] {
|
|
30
|
+
top: var(--zen-badge-offset-y, calc(var(--zen-badge-offset, 0px) * -1));
|
|
31
|
+
left: 50%;
|
|
32
|
+
transform: translateY(-50%) translateX(-50%);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
[topRight] {
|
|
36
|
+
top: var(--zen-badge-offset-y, calc(var(--zen-badge-offset, 0px) * -1));
|
|
37
|
+
right: var(--zen-badge-offset-x, calc(var(--zen-badge-offset, 0px) * -1));
|
|
38
|
+
transform: translateY(-50%) translateX(50%);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
[right] {
|
|
42
|
+
right: var(--zen-badge-offset-x, calc(var(--zen-badge-offset, 0px) * -1));
|
|
43
|
+
top: 50%;
|
|
44
|
+
transform: translateY(-50%) translateX(50%);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
[bottomRight] {
|
|
48
|
+
bottom: var(--zen-badge-offset-y, calc(var(--zen-badge-offset, 0px) * -1));
|
|
49
|
+
right: var(--zen-badge-offset-x, calc(var(--zen-badge-offset, 0px) * -1));
|
|
50
|
+
transform: translateY(50%) translateX(50%);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
[bottom] {
|
|
54
|
+
bottom: var(--zen-badge-offset-y, calc(var(--zen-badge-offset, 0px) * -1));
|
|
55
|
+
left: 50%;
|
|
56
|
+
transform: translateY(50%) translateX(-50%);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
[bottomLeft] {
|
|
60
|
+
bottom: var(--zen-badge-offset-y, calc(var(--zen-badge-offset, 0px) * -1));
|
|
61
|
+
left: var(--zen-badge-offset-x, calc(var(--zen-badge-offset, 0px) * -1));
|
|
62
|
+
transform: translateY(50%) translateX(-50%);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
[left] {
|
|
66
|
+
left: var(--zen-badge-offset-x, calc(var(--zen-badge-offset, 0px) * -1));
|
|
67
|
+
top: 50%;
|
|
68
|
+
transform: translateY(-50%) translateX(-50%);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { ZenBadgeComponent } from './badge.component';
|
|
4
|
+
|
|
5
|
+
describe('BadgeComponent', () => {
|
|
6
|
+
let component: ZenBadgeComponent;
|
|
7
|
+
let fixture: ComponentFixture<ZenBadgeComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
imports: [ZenBadgeComponent],
|
|
12
|
+
}).compileComponents();
|
|
13
|
+
|
|
14
|
+
fixture = TestBed.createComponent(ZenBadgeComponent);
|
|
15
|
+
component = fixture.componentInstance;
|
|
16
|
+
fixture.detectChanges();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should create', () => {
|
|
20
|
+
expect(component).toBeTruthy();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChangeDetectionStrategy,
|
|
3
|
+
Component,
|
|
4
|
+
ViewEncapsulation,
|
|
5
|
+
} from '@angular/core';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ZenBadgeComponent is a versatile Angular component used to display badges or indicators
|
|
9
|
+
* in various positions within its parent container. It allows for flexible placement
|
|
10
|
+
* of badge content such as icons, text, or other elements in the top-left, top,
|
|
11
|
+
* top-right, left, right, bottom-left, bottom, and bottom-right positions.
|
|
12
|
+
*
|
|
13
|
+
* This component offers standalone usage and is highly customizable through its
|
|
14
|
+
* template and styling. It leverages Angular's change detection strategy 'OnPush'
|
|
15
|
+
* for optimal performance.
|
|
16
|
+
*
|
|
17
|
+
* Additionally, it provides support for CSS variables to customize badge positioning
|
|
18
|
+
*
|
|
19
|
+
* ```css
|
|
20
|
+
* --zen-badge-offset: unset; // Controls the overall offset of the badge
|
|
21
|
+
* --zen-badge-offset-x: unset; // Controls the horizontal offset of the badge.
|
|
22
|
+
* --zen-badge-offset-y: unset; // Controls the vertical offset of the badge.
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example <zen-badge> Text <span bottom>🦆</span></zen-badge>
|
|
26
|
+
*
|
|
27
|
+
* @component
|
|
28
|
+
* @selector `zen-badge`,`[zenBadge]`
|
|
29
|
+
*
|
|
30
|
+
* @license BSD-2-Clause
|
|
31
|
+
* @author Konrad Stępień <kord.stp@gmail.com>
|
|
32
|
+
* @link https://github.com/Kordrad/ng-zen
|
|
33
|
+
*/
|
|
34
|
+
@Component({
|
|
35
|
+
selector: 'zen-badge,[zenBadge]',
|
|
36
|
+
standalone: true,
|
|
37
|
+
template: `
|
|
38
|
+
<ng-content />
|
|
39
|
+
<ng-content select="[topLeft]" />
|
|
40
|
+
<ng-content select="[top]" />
|
|
41
|
+
<ng-content select="[topRight]" />
|
|
42
|
+
<ng-content select="[left]" />
|
|
43
|
+
<ng-content select="[right]" />
|
|
44
|
+
<ng-content select="[bottomLeft]" />
|
|
45
|
+
<ng-content select="[bottom]" />
|
|
46
|
+
<ng-content select="[bottomRight]" />
|
|
47
|
+
`,
|
|
48
|
+
styleUrl: './badge.component.scss',
|
|
49
|
+
encapsulation: ViewEncapsulation.None,
|
|
50
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
51
|
+
})
|
|
52
|
+
export class ZenBadgeComponent {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './badge.component';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
$bg-color-hover: #333;
|
|
2
|
+
$bg-color: #000;
|
|
3
|
+
$color: #fff;
|
|
4
|
+
$padding: 8px 24px;
|
|
5
|
+
$shadow-hover: 0 0 0 3px rgb(0 123 255 / 50%);
|
|
6
|
+
$shadow: 0 2px 4px rgb(0 0 0 / 10%);
|
|
7
|
+
$transition-duration: 0.4s;
|
|
8
|
+
|
|
9
|
+
:host {
|
|
10
|
+
display: inline-block;
|
|
11
|
+
font-size: 14px;
|
|
12
|
+
font-weight: bold;
|
|
13
|
+
text-align: center;
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
border: none;
|
|
16
|
+
padding: $padding;
|
|
17
|
+
border-radius: 99999px;
|
|
18
|
+
transition: all $transition-duration ease;
|
|
19
|
+
background-color: $bg-color;
|
|
20
|
+
color: $color;
|
|
21
|
+
box-shadow: $shadow;
|
|
22
|
+
text-decoration: none;
|
|
23
|
+
outline: none;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
position: relative;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Hover state */
|
|
29
|
+
:host:hover {
|
|
30
|
+
background-color: $bg-color-hover;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Focus state */
|
|
34
|
+
:host:focus {
|
|
35
|
+
box-shadow: $shadow-hover;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Disabled state */
|
|
39
|
+
:host[disabled] {
|
|
40
|
+
cursor: not-allowed;
|
|
41
|
+
opacity: 0.6;
|
|
42
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { ZenButtonComponent } from './button.component';
|
|
4
|
+
|
|
5
|
+
describe('ButtonComponent', () => {
|
|
6
|
+
let component: ZenButtonComponent;
|
|
7
|
+
let fixture: ComponentFixture<ZenButtonComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
imports: [ZenButtonComponent],
|
|
12
|
+
}).compileComponents();
|
|
13
|
+
|
|
14
|
+
fixture = TestBed.createComponent(ZenButtonComponent);
|
|
15
|
+
component = fixture.componentInstance;
|
|
16
|
+
fixture.detectChanges();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should create', () => {
|
|
20
|
+
expect(component).toBeTruthy();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
// eslint-disable-next-line @angular-eslint/component-selector
|
|
5
|
+
selector: 'button[zen-button], a[zen-button]',
|
|
6
|
+
standalone: true,
|
|
7
|
+
template: ` <ng-content /> `,
|
|
8
|
+
styleUrl: './button.component.scss',
|
|
9
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
10
|
+
})
|
|
11
|
+
export class ZenButtonComponent {}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
import { ZenButtonComponent } from './button.component';
|
|
4
|
+
|
|
5
|
+
@NgModule({
|
|
6
|
+
imports: [ZenButtonComponent],
|
|
7
|
+
exports: [ZenButtonComponent],
|
|
8
|
+
})
|
|
9
|
+
export class ZenButtonModule {}
|
|
10
|
+
export * from './button.component';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './pin.component';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
zen-pin,
|
|
2
|
+
zen-pin.stream::before {
|
|
3
|
+
display: block;
|
|
4
|
+
height: 8px;
|
|
5
|
+
width: 8px;
|
|
6
|
+
border-radius: 50%;
|
|
7
|
+
background-color: #6b7280;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
zen-pin {
|
|
11
|
+
position: relative;
|
|
12
|
+
|
|
13
|
+
&.stream::before {
|
|
14
|
+
content: '';
|
|
15
|
+
position: absolute;
|
|
16
|
+
top: 50%;
|
|
17
|
+
left: 50%;
|
|
18
|
+
translate: -50% -50%;
|
|
19
|
+
animation: stream 1s ease-in-out infinite;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@keyframes stream {
|
|
24
|
+
75%,
|
|
25
|
+
100% {
|
|
26
|
+
transform: scale(2);
|
|
27
|
+
opacity: 0;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { ZenPinComponent } from './pin.component';
|
|
4
|
+
|
|
5
|
+
describe('PinComponent', () => {
|
|
6
|
+
let component: ZenPinComponent;
|
|
7
|
+
let fixture: ComponentFixture<ZenPinComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
imports: [ZenPinComponent],
|
|
12
|
+
}).compileComponents();
|
|
13
|
+
|
|
14
|
+
fixture = TestBed.createComponent(ZenPinComponent);
|
|
15
|
+
component = fixture.componentInstance;
|
|
16
|
+
fixture.detectChanges();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should create', () => {
|
|
20
|
+
expect(component).toBeTruthy();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
booleanAttribute,
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
HostBinding,
|
|
6
|
+
input,
|
|
7
|
+
ViewEncapsulation,
|
|
8
|
+
} from '@angular/core';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The ZenPinComponent represents a simple visual pin with a circular shape.
|
|
12
|
+
*
|
|
13
|
+
* ```html
|
|
14
|
+
* <zen-pin />
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @example <zen-pin />
|
|
18
|
+
* @component
|
|
19
|
+
* @selector `zen-pin`
|
|
20
|
+
*
|
|
21
|
+
* @license BSD-2-Clause
|
|
22
|
+
* @author Konrad Stępień <kord.stp@gmail.com>
|
|
23
|
+
* @link https://github.com/Kordrad/ng-zen
|
|
24
|
+
*/
|
|
25
|
+
@Component({
|
|
26
|
+
selector: 'zen-pin',
|
|
27
|
+
standalone: true,
|
|
28
|
+
imports: [],
|
|
29
|
+
template: ``,
|
|
30
|
+
styleUrl: './pin.component.scss',
|
|
31
|
+
encapsulation: ViewEncapsulation.None,
|
|
32
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
33
|
+
})
|
|
34
|
+
export class ZenPinComponent {
|
|
35
|
+
/**
|
|
36
|
+
* Displays waving stream animation
|
|
37
|
+
*/
|
|
38
|
+
readonly stream = input<boolean, boolean | 'true' | 'false' | ''>(false, {
|
|
39
|
+
transform: booleanAttribute,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
@HostBinding('class.stream')
|
|
43
|
+
get classStream() {
|
|
44
|
+
return this.stream();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
import { ZenSwitchComponent } from './zen-switch.component';
|
|
4
|
+
|
|
5
|
+
@NgModule({
|
|
6
|
+
imports: [ZenSwitchComponent],
|
|
7
|
+
exports: [ZenSwitchComponent],
|
|
8
|
+
})
|
|
9
|
+
export class ZenSwitchModule {}
|
|
10
|
+
export * from './zen-switch.component';
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Define SCSS variables for better maintainability
|
|
2
|
+
$switch-width: 36px;
|
|
3
|
+
$switch-height: 22px;
|
|
4
|
+
$slider-size: 16px;
|
|
5
|
+
$transition-duration: 0.4s;
|
|
6
|
+
$switch-bg-color: grey;
|
|
7
|
+
$switch-checked-bg-color: green;
|
|
8
|
+
$switch-disabled-bg-color: lightgrey;
|
|
9
|
+
$slider-bg-color: white;
|
|
10
|
+
|
|
11
|
+
// Other
|
|
12
|
+
$slider-padding: calc(($switch-height - $slider-size) / 2);
|
|
13
|
+
$slider-transform-distance: calc(
|
|
14
|
+
$switch-width - $slider-size - $slider-padding * 2
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
/* Switch container */
|
|
18
|
+
.switch {
|
|
19
|
+
position: relative;
|
|
20
|
+
display: inline-block;
|
|
21
|
+
width: $switch-width;
|
|
22
|
+
height: $switch-height;
|
|
23
|
+
background-color: $switch-bg-color;
|
|
24
|
+
border: none;
|
|
25
|
+
border-radius: 99999px; // force perfectly rounded
|
|
26
|
+
cursor: pointer;
|
|
27
|
+
transition: background-color $transition-duration;
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
outline: none;
|
|
31
|
+
&:focus {
|
|
32
|
+
box-shadow: 0 0 3px 2px rgba(21, 156, 228, 0.4);
|
|
33
|
+
}
|
|
34
|
+
*/
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Slider */
|
|
38
|
+
.slider {
|
|
39
|
+
position: absolute;
|
|
40
|
+
top: $slider-padding;
|
|
41
|
+
left: $slider-padding;
|
|
42
|
+
height: $slider-size;
|
|
43
|
+
width: $slider-size;
|
|
44
|
+
background-color: $slider-bg-color;
|
|
45
|
+
transition: transform $transition-duration;
|
|
46
|
+
border-radius: 50%;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Styles when the button is checked */
|
|
50
|
+
.switch[aria-checked='true'] {
|
|
51
|
+
background-color: $switch-checked-bg-color;
|
|
52
|
+
|
|
53
|
+
.slider {
|
|
54
|
+
transform: translateX($slider-transform-distance);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Styles when the button is disabled */
|
|
59
|
+
.switch[aria-disabled='true'] {
|
|
60
|
+
background-color: $switch-disabled-bg-color;
|
|
61
|
+
cursor: not-allowed;
|
|
62
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { ZenSwitchComponent } from './zen-switch.component';
|
|
4
|
+
|
|
5
|
+
describe('SwitchComponent', () => {
|
|
6
|
+
let component: ZenSwitchComponent;
|
|
7
|
+
let fixture: ComponentFixture<ZenSwitchComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
imports: [ZenSwitchComponent],
|
|
12
|
+
}).compileComponents();
|
|
13
|
+
|
|
14
|
+
fixture = TestBed.createComponent(ZenSwitchComponent);
|
|
15
|
+
component = fixture.componentInstance;
|
|
16
|
+
fixture.detectChanges();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should create', () => {
|
|
20
|
+
expect(component).toBeTruthy();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { NgIf } from '@angular/common';
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
forwardRef,
|
|
6
|
+
model,
|
|
7
|
+
} from '@angular/core';
|
|
8
|
+
import {
|
|
9
|
+
ControlValueAccessor,
|
|
10
|
+
FormsModule,
|
|
11
|
+
NG_VALUE_ACCESSOR,
|
|
12
|
+
} from '@angular/forms';
|
|
13
|
+
|
|
14
|
+
type OnChangeFn = (value: boolean) => void;
|
|
15
|
+
type OnTouchedFn = () => void;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* ZenSwitchComponent is a custom switch component that implements ControlValueAccessor to work seamlessly with Angular forms.
|
|
19
|
+
*
|
|
20
|
+
* @example <zen-switch />
|
|
21
|
+
*
|
|
22
|
+
* @export
|
|
23
|
+
* @class ZenSwitchComponent
|
|
24
|
+
* @implements {ControlValueAccessor}
|
|
25
|
+
*
|
|
26
|
+
* @license BSD-2-Clause
|
|
27
|
+
* @author Konrad Stępień <kord.stp@gmail.com>
|
|
28
|
+
* @link https://github.com/Kordrad/ng-zen
|
|
29
|
+
*/
|
|
30
|
+
@Component({
|
|
31
|
+
selector: 'zen-switch',
|
|
32
|
+
standalone: true,
|
|
33
|
+
templateUrl: './zen-switch.component.html',
|
|
34
|
+
styleUrl: './zen-switch.component.scss',
|
|
35
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
36
|
+
providers: [
|
|
37
|
+
{
|
|
38
|
+
provide: NG_VALUE_ACCESSOR,
|
|
39
|
+
useExisting: forwardRef(() => ZenSwitchComponent),
|
|
40
|
+
multi: true,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
imports: [FormsModule, NgIf],
|
|
44
|
+
})
|
|
45
|
+
export class ZenSwitchComponent implements ControlValueAccessor {
|
|
46
|
+
/** Model for the checked state of the switch. */
|
|
47
|
+
checked = model<boolean>(false);
|
|
48
|
+
|
|
49
|
+
/** Model for the disabled state of the switch. */
|
|
50
|
+
disabled = model<boolean>(false);
|
|
51
|
+
|
|
52
|
+
/** @ignore */
|
|
53
|
+
private onChange: OnChangeFn = () => {};
|
|
54
|
+
/** @ignore */
|
|
55
|
+
private onTouched: OnTouchedFn = () => {};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Writes a new value to the component.
|
|
59
|
+
* @ignore
|
|
60
|
+
*/
|
|
61
|
+
writeValue(value: boolean): void {
|
|
62
|
+
this.checked.set(value);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Registers a function to be called when the value changes.
|
|
67
|
+
* @ignore
|
|
68
|
+
*/
|
|
69
|
+
registerOnChange(fn: OnChangeFn): void {
|
|
70
|
+
this.onChange = fn;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Registers a function to be called when the component is touched.
|
|
75
|
+
* @ignore
|
|
76
|
+
*/
|
|
77
|
+
registerOnTouched(fn: OnTouchedFn): void {
|
|
78
|
+
this.onTouched = fn;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Sets the disabled state of the component.
|
|
83
|
+
* @ignore
|
|
84
|
+
*/
|
|
85
|
+
setDisabledState(isDisabled: boolean): void {
|
|
86
|
+
this.disabled.set(isDisabled);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Toggles the switch value and notifies the change.
|
|
91
|
+
*/
|
|
92
|
+
onToggle(check?: boolean): void {
|
|
93
|
+
if (this.disabled()) return;
|
|
94
|
+
|
|
95
|
+
const value = check ?? !this.checked();
|
|
96
|
+
|
|
97
|
+
this.checked.set(value);
|
|
98
|
+
this.onChange(value);
|
|
99
|
+
this.onTouched();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Handles keyboard events for accessibility.
|
|
104
|
+
*/
|
|
105
|
+
onKeyDown(event: KeyboardEvent): void {
|
|
106
|
+
switch (event.code) {
|
|
107
|
+
case 'Enter':
|
|
108
|
+
case 'Space': {
|
|
109
|
+
event.preventDefault();
|
|
110
|
+
this.onToggle();
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case 'ArrowRight': {
|
|
114
|
+
this.onToggle(true);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case 'ArrowLeft': {
|
|
118
|
+
this.onToggle(false);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { ZenTagComponent } from './tag.component';
|
|
4
|
+
|
|
5
|
+
describe('ZenTagComponent', () => {
|
|
6
|
+
let component: ZenTagComponent;
|
|
7
|
+
let fixture: ComponentFixture<ZenTagComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
imports: [ZenTagComponent],
|
|
12
|
+
}).compileComponents();
|
|
13
|
+
|
|
14
|
+
fixture = TestBed.createComponent(ZenTagComponent);
|
|
15
|
+
component = fixture.componentInstance;
|
|
16
|
+
fixture.detectChanges();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should create', () => {
|
|
20
|
+
expect(component).toBeTruthy();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The `ZenTagComponent` is a reusable UI component designed to display a tag or label.
|
|
5
|
+
* It allows for custom content to be projected inside the tag.
|
|
6
|
+
*
|
|
7
|
+
* ```html
|
|
8
|
+
* <zen-tag>...</zen-tag>
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* @example <zen-tag>Simple tag</zen-tag>
|
|
12
|
+
* @component
|
|
13
|
+
* @selector `zen-tag`
|
|
14
|
+
*
|
|
15
|
+
* @license BSD-2-Clause
|
|
16
|
+
* @author Konrad Stępień <kord.stp@gmail.com>
|
|
17
|
+
* @link https://github.com/Kordrad/ng-zen
|
|
18
|
+
*/
|
|
19
|
+
@Component({
|
|
20
|
+
selector: 'zen-tag',
|
|
21
|
+
standalone: true,
|
|
22
|
+
template: `<ng-content />`,
|
|
23
|
+
styleUrl: './tag.component.scss',
|
|
24
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
25
|
+
})
|
|
26
|
+
export class ZenTagComponent {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../projects/cli/schematics/components/index.ts"],"names":[],"mappings":"AACA,OAAO,EAML,IAAI,EAEL,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAElE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAoB1E"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.componentGenerator = void 0;
|
|
4
|
+
const core_1 = require("@angular-devkit/core");
|
|
5
|
+
const schematics_1 = require("@angular-devkit/schematics");
|
|
6
|
+
function componentGenerator(options) {
|
|
7
|
+
return () => {
|
|
8
|
+
const componentsSource = options.components.map(component => {
|
|
9
|
+
const rules = [
|
|
10
|
+
(0, schematics_1.applyTemplates)(Object.assign({ name: component, localeDate: new Date().toLocaleString() }, core_1.strings)),
|
|
11
|
+
(0, schematics_1.move)((0, core_1.normalize)(`${options.path}/${component}`)),
|
|
12
|
+
];
|
|
13
|
+
const componentTemplateSource = (0, schematics_1.apply)((0, schematics_1.url)(`./files/${component}`), rules);
|
|
14
|
+
const genericTemplates = (0, schematics_1.apply)((0, schematics_1.url)(`./templates`), rules);
|
|
15
|
+
return (0, schematics_1.chain)([componentTemplateSource, genericTemplates].map(schematics_1.mergeWith));
|
|
16
|
+
});
|
|
17
|
+
return (0, schematics_1.chain)(componentsSource);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
exports.componentGenerator = componentGenerator;
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../projects/cli/schematics/components/index.ts"],"names":[],"mappings":";;;AAAA,+CAA0D;AAC1D,2DAQoC;AAIpC,SAAgB,kBAAkB,CAAC,OAAiC;IAClE,OAAO,GAAG,EAAE;QACV,MAAM,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;YAC1D,MAAM,KAAK,GAAW;gBACpB,IAAA,2BAAc,kBACZ,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,cAAc,EAAE,IACpC,cAAO,EACV;gBACF,IAAA,iBAAI,EAAC,IAAA,gBAAS,EAAC,GAAG,OAAO,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC,CAAC;aAChD,CAAC;YAEF,MAAM,uBAAuB,GAAG,IAAA,kBAAK,EAAC,IAAA,gBAAG,EAAC,WAAW,SAAS,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;YAC1E,MAAM,gBAAgB,GAAG,IAAA,kBAAK,EAAC,IAAA,gBAAG,EAAC,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC;YAE1D,OAAO,IAAA,kBAAK,EAAC,CAAC,uBAAuB,EAAE,gBAAgB,CAAC,CAAC,GAAG,CAAC,sBAAS,CAAC,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,OAAO,IAAA,kBAAK,EAAC,gBAAgB,CAAC,CAAC;IACjC,CAAC,CAAC;AACJ,CAAC;AApBD,gDAoBC","sourcesContent":["import { normalize, strings } from '@angular-devkit/core';\r\nimport {\r\n apply,\r\n applyTemplates,\r\n chain,\r\n mergeWith,\r\n move,\r\n Rule,\r\n url,\r\n} from '@angular-devkit/schematics';\r\n\r\nimport { ComponentGeneratorSchema } from './components-generator';\r\n\r\nexport function componentGenerator(options: ComponentGeneratorSchema): Rule {\r\n return () => {\r\n const componentsSource = options.components.map(component => {\r\n const rules: Rule[] = [\r\n applyTemplates({\r\n name: component,\r\n localeDate: new Date().toLocaleString(),\r\n ...strings,\r\n }),\r\n move(normalize(`${options.path}/${component}`)),\r\n ];\r\n\r\n const componentTemplateSource = apply(url(`./files/${component}`), rules);\r\n const genericTemplates = apply(url(`./templates`), rules);\r\n\r\n return chain([componentTemplateSource, genericTemplates].map(mergeWith));\r\n });\r\n\r\n return chain(componentsSource);\r\n };\r\n}\r\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/schema",
|
|
3
|
+
"$id": "NgZenCliComponents",
|
|
4
|
+
"title": "Schema to create Zen UI components",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"description": "Adds Zen UI component 📦",
|
|
7
|
+
"properties": {
|
|
8
|
+
"components": {
|
|
9
|
+
"description": "Select component to generate (e.g: --components=avatar pin)",
|
|
10
|
+
"type": "array",
|
|
11
|
+
"items": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"enum": ["avatar", "badge", "button", "pin", "switch", "tag"]
|
|
14
|
+
},
|
|
15
|
+
"multiselect": true,
|
|
16
|
+
"x-prompt": "Which component should be generated?"
|
|
17
|
+
},
|
|
18
|
+
"path": {
|
|
19
|
+
"description": "Where should be created the components",
|
|
20
|
+
"type": "string",
|
|
21
|
+
"format": "path",
|
|
22
|
+
"default": "/projects/ng-zen/components"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# <%= classify(name) %> component
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
Generated by `@ng-zen/cli` on <%= localeDate %>
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
<%= classify(name) %> component was generated by
|
|
11
|
+
```bash
|
|
12
|
+
ng generate @ng-zen/cli:component --components=<%= name %>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This component is part of a larger set of UI components aimed at enhancing and streamlining the development process in Angular applications.
|
|
16
|
+
|
|
17
|
+
More information you can find here
|
|
18
|
+
```bash
|
|
19
|
+
ng generate @ng-zen/cli:component --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
To generate other components, ensure that you have the `@ng-zen/cli` library installed. You can add it to your project with the following command:
|
|
25
|
+
```bash
|
|
26
|
+
ng add @ng-zen/cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
then you can generate components via
|
|
30
|
+
```bash
|
|
31
|
+
ng generate @ng-zen/cli:component
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
## Author
|
|
36
|
+
|
|
37
|
+
This component was generated by the `@ng-zen/cli` tool developed by Konrad Stępień.
|
|
38
|
+
|
|
39
|
+
This code is licensed under the BSD-2-Clause license. See the [LICENSE](https://github.com/Kordrad/ng-zen/blob/master/projects/cli/LICENSE) file for more details.
|
|
40
|
+
|
|
41
|
+
Source code can be found [here](https://github.com/Kordrad/ng-zen).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../projects/cli/schematics/ng-add/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAA0B,MAAM,4BAA4B,CAAC;AAG1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,wBAAgB,KAAK,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAQzD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ngAdd = void 0;
|
|
4
|
+
const add_path_to_tsconfig_util_1 = require("../utils/add-path-to-tsconfig.util");
|
|
5
|
+
function ngAdd(options) {
|
|
6
|
+
return (tree, _context) => {
|
|
7
|
+
_context.logger.info('Adding library to the project');
|
|
8
|
+
(0, add_path_to_tsconfig_util_1.addPathToTsconfigUtil)(tree, 'ng-zen/*', [`${options.path}/*`]);
|
|
9
|
+
return tree;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
exports.ngAdd = ngAdd;
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../projects/cli/schematics/ng-add/index.ts"],"names":[],"mappings":";;;AAEA,kFAA2E;AAG3E,SAAgB,KAAK,CAAC,OAA6B;IACjD,OAAO,CAAC,IAAU,EAAE,QAA0B,EAAE,EAAE;QAChD,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAEtD,IAAA,iDAAqB,EAAC,IAAI,EAAE,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;QAE/D,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC;AARD,sBAQC","sourcesContent":["import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\r\n\r\nimport { addPathToTsconfigUtil } from '../utils/add-path-to-tsconfig.util';\r\nimport { NgZenGeneratorSchema } from './ng-zen-generator';\r\n\r\nexport function ngAdd(options: NgZenGeneratorSchema): Rule {\r\n return (tree: Tree, _context: SchematicContext) => {\r\n _context.logger.info('Adding library to the project');\r\n\r\n addPathToTsconfigUtil(tree, 'ng-zen/*', [`${options.path}/*`]);\r\n\r\n return tree;\r\n };\r\n}\r\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ng-zen-generator.d.ts","sourceRoot":"","sources":["../../../../../projects/cli/schematics/ng-add/ng-zen-generator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;CACd"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ng-zen-generator.js","sourceRoot":"","sources":["../../../../../projects/cli/schematics/ng-add/ng-zen-generator.ts"],"names":[],"mappings":"","sourcesContent":["export interface NgZenGeneratorSchema {\r\n path: string;\r\n}\r\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/schema",
|
|
3
|
+
"$id": "NgZenCliComponents",
|
|
4
|
+
"title": "Schema to create Zen UI library",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"description": "Adds Zen CLI library and configure project 📦",
|
|
7
|
+
"properties": {
|
|
8
|
+
"path": {
|
|
9
|
+
"description": "Where should be created the library",
|
|
10
|
+
"type": "string",
|
|
11
|
+
"format": "path",
|
|
12
|
+
"default": "projects/ng-zen"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-path-to-tsconfig.util.d.ts","sourceRoot":"","sources":["../../../../../projects/cli/schematics/utils/add-path-to-tsconfig.util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAC;AAElD,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EAAE,GACd,IAAI,CA+CN"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addPathToTsconfigUtil = void 0;
|
|
4
|
+
const schematics_1 = require("@angular-devkit/schematics");
|
|
5
|
+
function addPathToTsconfigUtil(tree, key, value) {
|
|
6
|
+
const tsconfigPath = 'tsconfig.json';
|
|
7
|
+
// Check if tsconfig.json exists
|
|
8
|
+
if (!tree.exists(tsconfigPath)) {
|
|
9
|
+
throw new schematics_1.SchematicsException('tsconfig.json does not exist');
|
|
10
|
+
}
|
|
11
|
+
// Read tsconfig.json content as string
|
|
12
|
+
const tsconfigBuffer = tree.read(tsconfigPath);
|
|
13
|
+
if (!tsconfigBuffer) {
|
|
14
|
+
throw new schematics_1.SchematicsException('Failed to read tsconfig.json');
|
|
15
|
+
}
|
|
16
|
+
let tsconfigContent = tsconfigBuffer.toString('utf-8');
|
|
17
|
+
// Extract and preserve the comment
|
|
18
|
+
const commentMatch = tsconfigContent.match(/\/\*[\s\S]*?\*\//);
|
|
19
|
+
const comment = commentMatch ? commentMatch[0] : '';
|
|
20
|
+
// Remove comment from content to parse JSON
|
|
21
|
+
tsconfigContent = tsconfigContent.replace(comment, '');
|
|
22
|
+
// Parse tsconfig.json content
|
|
23
|
+
let tsconfig;
|
|
24
|
+
try {
|
|
25
|
+
tsconfig = JSON.parse(tsconfigContent);
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
throw new schematics_1.SchematicsException('Failed to parse tsconfig.json');
|
|
29
|
+
}
|
|
30
|
+
// Modify compilerOptions.paths to add your new mapping
|
|
31
|
+
if (!tsconfig.compilerOptions) {
|
|
32
|
+
tsconfig.compilerOptions = {};
|
|
33
|
+
}
|
|
34
|
+
if (!tsconfig.compilerOptions.paths) {
|
|
35
|
+
tsconfig.compilerOptions.paths = {};
|
|
36
|
+
}
|
|
37
|
+
tsconfig.compilerOptions.paths[key] = value;
|
|
38
|
+
// Convert tsconfig back to JSON string
|
|
39
|
+
tsconfigContent = JSON.stringify(tsconfig, null, 2);
|
|
40
|
+
// Ensure the preserved comment is prepended to the JSON string
|
|
41
|
+
tsconfigContent = `${comment}\n${tsconfigContent}`;
|
|
42
|
+
// Write back to tsconfig.json
|
|
43
|
+
tree.overwrite(tsconfigPath, tsconfigContent);
|
|
44
|
+
}
|
|
45
|
+
exports.addPathToTsconfigUtil = addPathToTsconfigUtil;
|
|
46
|
+
//# sourceMappingURL=add-path-to-tsconfig.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-path-to-tsconfig.util.js","sourceRoot":"","sources":["../../../../../projects/cli/schematics/utils/add-path-to-tsconfig.util.ts"],"names":[],"mappings":";;;AAAA,2DAAiE;AAGjE,SAAgB,qBAAqB,CACnC,IAAU,EACV,GAAW,EACX,KAAe;IAEf,MAAM,YAAY,GAAG,eAAe,CAAC;IAErC,gCAAgC;IAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,gCAAmB,CAAC,8BAA8B,CAAC,CAAC;IAChE,CAAC;IAED,uCAAuC;IACvC,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC/C,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,gCAAmB,CAAC,8BAA8B,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,eAAe,GAAG,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAEvD,mCAAmC;IACnC,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEpD,4CAA4C;IAC5C,eAAe,GAAG,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAEvD,8BAA8B;IAC9B,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,gCAAmB,CAAC,+BAA+B,CAAC,CAAC;IACjE,CAAC;IAED,uDAAuD;IACvD,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC;QAC9B,QAAQ,CAAC,eAAe,GAAG,EAAE,CAAC;IAChC,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QACpC,QAAQ,CAAC,eAAe,CAAC,KAAK,GAAG,EAAE,CAAC;IACtC,CAAC;IACD,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAE5C,uCAAuC;IACvC,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEpD,+DAA+D;IAC/D,eAAe,GAAG,GAAG,OAAO,KAAK,eAAe,EAAE,CAAC;IAEnD,8BAA8B;IAC9B,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;AAChD,CAAC;AAnDD,sDAmDC","sourcesContent":["import { SchematicsException } from '@angular-devkit/schematics';\r\nimport { Tree } from '@angular-devkit/schematics';\r\n\r\nexport function addPathToTsconfigUtil(\r\n tree: Tree,\r\n key: string,\r\n value: string[]\r\n): void {\r\n const tsconfigPath = 'tsconfig.json';\r\n\r\n // Check if tsconfig.json exists\r\n if (!tree.exists(tsconfigPath)) {\r\n throw new SchematicsException('tsconfig.json does not exist');\r\n }\r\n\r\n // Read tsconfig.json content as string\r\n const tsconfigBuffer = tree.read(tsconfigPath);\r\n if (!tsconfigBuffer) {\r\n throw new SchematicsException('Failed to read tsconfig.json');\r\n }\r\n let tsconfigContent = tsconfigBuffer.toString('utf-8');\r\n\r\n // Extract and preserve the comment\r\n const commentMatch = tsconfigContent.match(/\\/\\*[\\s\\S]*?\\*\\//);\r\n const comment = commentMatch ? commentMatch[0] : '';\r\n\r\n // Remove comment from content to parse JSON\r\n tsconfigContent = tsconfigContent.replace(comment, '');\r\n\r\n // Parse tsconfig.json content\r\n let tsconfig;\r\n try {\r\n tsconfig = JSON.parse(tsconfigContent);\r\n } catch (e) {\r\n throw new SchematicsException('Failed to parse tsconfig.json');\r\n }\r\n\r\n // Modify compilerOptions.paths to add your new mapping\r\n if (!tsconfig.compilerOptions) {\r\n tsconfig.compilerOptions = {};\r\n }\r\n if (!tsconfig.compilerOptions.paths) {\r\n tsconfig.compilerOptions.paths = {};\r\n }\r\n tsconfig.compilerOptions.paths[key] = value;\r\n\r\n // Convert tsconfig back to JSON string\r\n tsconfigContent = JSON.stringify(tsconfig, null, 2);\r\n\r\n // Ensure the preserved comment is prepended to the JSON string\r\n tsconfigContent = `${comment}\\n${tsconfigContent}`;\r\n\r\n // Write back to tsconfig.json\r\n tree.overwrite(tsconfigPath, tsconfigContent);\r\n}\r\n"]}
|