@asor-studio/asor-cli 1.0.0
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/LICENSE +24 -0
- package/README.md +293 -0
- package/cli-command/generate-atom.js +2 -0
- package/cli-command/generate-molecule.js +2 -0
- package/cli-command/generate-organism.js +2 -0
- package/cli-command/generate-page.js +2 -0
- package/cli-command/setup-asor-core.js +2 -0
- package/cli.js +2 -0
- package/gen-template/generate-atom/atom.html.template +26 -0
- package/gen-template/generate-atom/atom.ts.template +69 -0
- package/gen-template/generate-molecule/molecule.html.template +41 -0
- package/gen-template/generate-molecule/molecule.ts.template +69 -0
- package/gen-template/generate-organism/organism.html.template +41 -0
- package/gen-template/generate-organism/organism.ts.template +69 -0
- package/gen-template/generate-page/page.component.html.template +63 -0
- package/gen-template/generate-page/page.component.ts.template +56 -0
- package/gen-template/setup-asor-core/src/app/app.config.ts.template +46 -0
- package/gen-template/setup-asor-core/src/app/app.routes.ts.template +40 -0
- package/gen-template/setup-asor-core/src/app/config/app-asor.config.ts.template +64 -0
- package/gen-template/setup-asor-core/src/app/config/app-cache.config.ts.template +26 -0
- package/gen-template/setup-asor-core/src/app/config/app-state.config.ts.template +26 -0
- package/gen-template/setup-asor-core/src/app/config/app.config.ts.template +62 -0
- package/gen-template/setup-asor-core/src/app/config/interfaces/app-state.interfaces.ts.template +5 -0
- package/gen-template/setup-asor-core/src/app/molecules/molecule-sample-widget/sample-widget.molecule.html.template +84 -0
- package/gen-template/setup-asor-core/src/app/molecules/molecule-sample-widget/sample-widget.molecule.ts.template +56 -0
- package/gen-template/setup-asor-core/src/app/pages/page-home/asor-logo.ts.template +1 -0
- package/gen-template/setup-asor-core/src/app/pages/page-home/home.component.html.template +521 -0
- package/gen-template/setup-asor-core/src/app/pages/page-home/home.component.ts.template +99 -0
- package/gen-template/setup-asor-core/src/assets/i18n/app/molecule-sample-widget/en.json.template +7 -0
- package/gen-template/setup-asor-core/src/assets/i18n/app/molecule-sample-widget/it.json.template +7 -0
- package/gen-template/setup-asor-core/src/assets/i18n/app/page-home/en.json.template +19 -0
- package/gen-template/setup-asor-core/src/assets/i18n/app/page-home/it.json.template +19 -0
- package/package.json +31 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
/*
|
|
3
|
+
* IMPORTANT:
|
|
4
|
+
* This CSS block is only a minimal base generated by the template.
|
|
5
|
+
* In a real project, styles should be moved to a dedicated file
|
|
6
|
+
* based on the standard chosen by the team: CSS, SCSS, Sass, Less,
|
|
7
|
+
* or handled through global styles, utility classes, a design system, or inline styles.
|
|
8
|
+
*/
|
|
9
|
+
.__KEBAB__-organism {
|
|
10
|
+
display: grid;
|
|
11
|
+
gap: 0.65rem;
|
|
12
|
+
width: min(100%, 40rem);
|
|
13
|
+
padding: 1.15rem;
|
|
14
|
+
border: 1px solid rgba(226, 232, 240, 0.95);
|
|
15
|
+
border-radius: 1rem;
|
|
16
|
+
background: #ffffff;
|
|
17
|
+
color: #0f172a;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.__KEBAB__-title,
|
|
21
|
+
.__KEBAB__-description {
|
|
22
|
+
margin: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.__KEBAB__-title {
|
|
26
|
+
font-size: 1.15rem;
|
|
27
|
+
line-height: 1.2;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.__KEBAB__-description {
|
|
31
|
+
max-width: 46ch;
|
|
32
|
+
color: #475569;
|
|
33
|
+
font-size: 0.94rem;
|
|
34
|
+
line-height: 1.5;
|
|
35
|
+
}
|
|
36
|
+
</style>
|
|
37
|
+
|
|
38
|
+
<section class="__KEBAB__-organism">
|
|
39
|
+
<h2 class="__KEBAB__-title">{{ '__ROUTE_KEY__.TITLE' | translate }}</h2>
|
|
40
|
+
<p class="__KEBAB__-description">{{ '__ROUTE_KEY__.WELCOME' | translate }}</p>
|
|
41
|
+
</section>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { __BASE_CLASS_NAME__, TranslatePipe } from '@asor-studio/asor-core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Organism Component: __PASCAL__Organism
|
|
7
|
+
*
|
|
8
|
+
* ATOMIC DESIGN ROLE:
|
|
9
|
+
* An Organism is a complex component composed of molecules and/or atoms, forming a distinct section of the interface (e.g., a header, a sidebar).
|
|
10
|
+
* It represents the final level of reusable UI blocks before the Page level.
|
|
11
|
+
*
|
|
12
|
+
* I18N / TRANSLATIONS:
|
|
13
|
+
* Translations for this organism can be found (or added) in:
|
|
14
|
+
* `assets/i18n/<prefix>/organism-__KEBAB__/<lang>.json`
|
|
15
|
+
*
|
|
16
|
+
* ROUTE CONFIGURATION & PAGE BELONGING:
|
|
17
|
+
* To see which page(s) this organism belongs to, check `src/app/app.routes.ts`.
|
|
18
|
+
* It is injected into a page's metadata via the `data.Organisms` array.
|
|
19
|
+
* Look for the following placeholder in the routes file:
|
|
20
|
+
* `// [ASOR-INJECT:ORGANISM-DEFS(<page-name>)]`
|
|
21
|
+
*/
|
|
22
|
+
@Component({
|
|
23
|
+
selector: 'app-__KEBAB__',
|
|
24
|
+
standalone: true,
|
|
25
|
+
imports: [CommonModule, TranslatePipe],
|
|
26
|
+
templateUrl: './__KEBAB__.organism.html',
|
|
27
|
+
})
|
|
28
|
+
export class __PASCAL__Organism __BASE_CLASS_EXTENDS__ {
|
|
29
|
+
/**
|
|
30
|
+
* Unique identifier for the component class.
|
|
31
|
+
* CRITICAL for asor-core: used by the framework to identify this component
|
|
32
|
+
* within route metadata and correctly resolve its configuration/i18n paths.
|
|
33
|
+
*/
|
|
34
|
+
public static override readonly className: string = '__PASCAL__Organism';
|
|
35
|
+
|
|
36
|
+
constructor() {
|
|
37
|
+
super();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Lifecycle hook called when the component view is about to enter at a generic level.
|
|
42
|
+
* Used for system-wide initialization logic common to all asor components.
|
|
43
|
+
*/
|
|
44
|
+
override baseCompViewEnter(): void { }
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Lifecycle hook called when the component view is about to leave at a generic level.
|
|
48
|
+
* Used for system-wide cleanup logic common to all asor components.
|
|
49
|
+
* Calls super.baseCompViewLeave() to ensure proper cleanup of base class / storage resources.
|
|
50
|
+
*/
|
|
51
|
+
override baseCompViewLeave(): void {
|
|
52
|
+
super.baseCompViewLeave();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Specialized lifecycle hook for Organism components called when the view is about to enter.
|
|
57
|
+
* Use this for organism-specific initialization logic (e.g. orchestration of children datasets).
|
|
58
|
+
*/
|
|
59
|
+
override baseOrganismViewWillEnter(): void { }
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Specialized lifecycle hook for Organism components called when the view is about to leave.
|
|
63
|
+
* Use this for organism-specific cleanup logic.
|
|
64
|
+
* Calls super.baseOrganismViewWillLeave() to ensure proper cleanup of base class / storage resources.
|
|
65
|
+
*/
|
|
66
|
+
override baseOrganismViewWillLeave(): void {
|
|
67
|
+
super.baseOrganismViewWillLeave();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
/*
|
|
3
|
+
* IMPORTANT:
|
|
4
|
+
* This CSS block is only a minimal base generated by the template.
|
|
5
|
+
* In a real project, styles should be moved to a dedicated file
|
|
6
|
+
* based on the standard chosen by the team: CSS, SCSS, Sass, Less,
|
|
7
|
+
* or handled through global styles, utility classes, a design system, or inline styles.
|
|
8
|
+
*/
|
|
9
|
+
.__KEBAB__-page {
|
|
10
|
+
display: grid;
|
|
11
|
+
gap: 1rem;
|
|
12
|
+
min-height: 100%;
|
|
13
|
+
padding: 1.25rem;
|
|
14
|
+
justify-items: center;
|
|
15
|
+
background: #f8fafc;
|
|
16
|
+
color: #111827;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.__KEBAB__-surface {
|
|
20
|
+
display: grid;
|
|
21
|
+
gap: 0.65rem;
|
|
22
|
+
width: min(100%, 44rem);
|
|
23
|
+
padding: 1.25rem;
|
|
24
|
+
border: 1px solid rgba(226, 232, 240, 0.9);
|
|
25
|
+
border-radius: 1rem;
|
|
26
|
+
background: #ffffff;
|
|
27
|
+
color: inherit;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.__KEBAB__-eyebrow {
|
|
31
|
+
margin: 0;
|
|
32
|
+
font-size: 0.72rem;
|
|
33
|
+
font-weight: 700;
|
|
34
|
+
letter-spacing: 0.08em;
|
|
35
|
+
color: #8b5cf6;
|
|
36
|
+
text-transform: uppercase;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.__KEBAB__-title,
|
|
40
|
+
.__KEBAB__-description {
|
|
41
|
+
margin: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.__KEBAB__-title {
|
|
45
|
+
font-size: 1.5rem;
|
|
46
|
+
line-height: 1.2;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.__KEBAB__-description {
|
|
50
|
+
max-width: 52ch;
|
|
51
|
+
color: #4b5563;
|
|
52
|
+
font-size: 0.94rem;
|
|
53
|
+
line-height: 1.5;
|
|
54
|
+
}
|
|
55
|
+
</style>
|
|
56
|
+
|
|
57
|
+
<main class="__KEBAB__-page">
|
|
58
|
+
<section class="__KEBAB__-surface">
|
|
59
|
+
<p class="__KEBAB__-eyebrow">Page</p>
|
|
60
|
+
<h1 class="__KEBAB__-title">{{ '__ROUTE_KEY__.TITLE' | translate }}</h1>
|
|
61
|
+
<p class="__KEBAB__-description">{{ '__ROUTE_KEY__.WELCOME' | translate }}</p>
|
|
62
|
+
</section>
|
|
63
|
+
</main>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { TranslatePipe } from '@asor-studio/asor-core';
|
|
4
|
+
import { __BASE_CLASS_NAME__, ConsoleLogsUtility } from '@asor-studio/asor-core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Page Component: Page__PASCAL__Component
|
|
8
|
+
*
|
|
9
|
+
* ATOMIC DESIGN ROLE:
|
|
10
|
+
* A Page is the highest level of the atomic design hierarchy. It orchestrates atoms, molecules, and organisms
|
|
11
|
+
* to form a complete functional view or screen of the application.
|
|
12
|
+
*
|
|
13
|
+
* I18N / TRANSLATIONS:
|
|
14
|
+
* Translations for this page can be found (or added) in:
|
|
15
|
+
* `assets/i18n/<prefix>/page-__KEBAB__/<lang>.json`
|
|
16
|
+
*
|
|
17
|
+
* ROUTE CONFIGURATION:
|
|
18
|
+
* This page is directly mapped to a route in `src/app/app.routes.ts`.
|
|
19
|
+
* Configuration for its components (Atoms, Molecules, Organisms) is managed via the `data` property of the route.
|
|
20
|
+
*/
|
|
21
|
+
@Component({
|
|
22
|
+
selector: 'app-__KEBAB__-page',
|
|
23
|
+
standalone: true,
|
|
24
|
+
imports: [CommonModule, TranslatePipe],
|
|
25
|
+
templateUrl: './__KEBAB__.component.html',
|
|
26
|
+
})
|
|
27
|
+
export class Page__PASCAL__Component __BASE_CLASS_EXTENDS__ {
|
|
28
|
+
/**
|
|
29
|
+
* Unique identifier for the component class.
|
|
30
|
+
* CRITICAL for asor-core: used by the framework to identify this component
|
|
31
|
+
* within route metadata and correctly resolve its configuration/i18n paths.
|
|
32
|
+
*/
|
|
33
|
+
public static override readonly className: string = 'Page__PASCAL__Component';
|
|
34
|
+
|
|
35
|
+
constructor() {
|
|
36
|
+
super();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Lifecycle hook called when the component view is about to enter at a generic level.
|
|
41
|
+
* Used for system-wide initialization logic common to all asor components.
|
|
42
|
+
*/
|
|
43
|
+
override baseCompViewEnter(): void {
|
|
44
|
+
super.baseCompViewEnter();
|
|
45
|
+
ConsoleLogsUtility.info(this, '__PASCAL__ page loaded!');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Lifecycle hook called when the component view is about to leave at a generic level.
|
|
50
|
+
* Used for system-wide cleanup logic common to all asor components.
|
|
51
|
+
* Calls super.baseCompViewLeave() to ensure proper cleanup of base class / storage resources.
|
|
52
|
+
*/
|
|
53
|
+
override baseCompViewLeave(): void {
|
|
54
|
+
super.baseCompViewLeave();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ApplicationConfig, APP_INITIALIZER, provideZonelessChangeDetection } from '@angular/core';
|
|
2
|
+
import { provideRouter, withComponentInputBinding } from '@angular/router';
|
|
3
|
+
import { provideHttpClient, withInterceptorsFromDi, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
4
|
+
import {
|
|
5
|
+
StateService,
|
|
6
|
+
CacheInterceptor,
|
|
7
|
+
ErrorInterceptor,
|
|
8
|
+
MockHttpInterceptor,
|
|
9
|
+
MockOrchestratorService,
|
|
10
|
+
} from '@asor-studio/asor-core';
|
|
11
|
+
import { routes } from './app.routes';
|
|
12
|
+
import { initializeAsorCoreApp } from './config/app-asor.config';
|
|
13
|
+
import { APP_BASE_HREF } from '@angular/common';
|
|
14
|
+
|
|
15
|
+
export const appConfig: ApplicationConfig = {
|
|
16
|
+
providers: [
|
|
17
|
+
{
|
|
18
|
+
provide: APP_INITIALIZER,
|
|
19
|
+
useFactory: initializeAsorCoreApp,
|
|
20
|
+
deps: [StateService, MockOrchestratorService],
|
|
21
|
+
multi: true,
|
|
22
|
+
},
|
|
23
|
+
provideZonelessChangeDetection(),
|
|
24
|
+
provideRouter(routes, withComponentInputBinding()),
|
|
25
|
+
provideHttpClient(withInterceptorsFromDi()),
|
|
26
|
+
{
|
|
27
|
+
provide: HTTP_INTERCEPTORS,
|
|
28
|
+
useClass: MockHttpInterceptor,
|
|
29
|
+
multi: true,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
provide: HTTP_INTERCEPTORS,
|
|
33
|
+
useClass: CacheInterceptor,
|
|
34
|
+
multi: true,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
provide: HTTP_INTERCEPTORS,
|
|
38
|
+
useClass: ErrorInterceptor,
|
|
39
|
+
multi: true,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
provide: APP_BASE_HREF,
|
|
43
|
+
useValue: '/', // Customize for your application
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Routes } from '@angular/router';
|
|
2
|
+
import { AuthGuard, IAsorRoute } from '@asor-studio/asor-core';
|
|
3
|
+
import { AppConfig } from './config/app.config';
|
|
4
|
+
import { PageHomeComponent } from './pages/page-home/home.component';
|
|
5
|
+
import { AppStateConnectionSystem } from './config/app-state.config';
|
|
6
|
+
import { SampleWidgetMolecule } from './molecules/molecule-sample-widget/sample-widget.molecule';
|
|
7
|
+
// [ASOR-INJECT:ROUTE-IMPORTS]
|
|
8
|
+
|
|
9
|
+
export const routes: Routes = [
|
|
10
|
+
{
|
|
11
|
+
path: '',
|
|
12
|
+
redirectTo: AppConfig.Route.HOME,
|
|
13
|
+
pathMatch: 'full',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
path: AppConfig.Route.HOME,
|
|
17
|
+
component: PageHomeComponent,
|
|
18
|
+
data: {
|
|
19
|
+
I18nPath: [AppConfig.TranslationUrl.HOME],
|
|
20
|
+
ConnectDataSet: AppStateConnectionSystem,
|
|
21
|
+
Components: [
|
|
22
|
+
// [ASOR-INJECT:COMPONENT-DEFS(home)]
|
|
23
|
+
],
|
|
24
|
+
Molecules: [
|
|
25
|
+
{
|
|
26
|
+
Molecule: SampleWidgetMolecule,
|
|
27
|
+
I18nPath: [AppConfig.TranslationUrl.SAMPLE_WIDGET],
|
|
28
|
+
},
|
|
29
|
+
// [ASOR-INJECT:MOLECULE-DEFS(home)]
|
|
30
|
+
],
|
|
31
|
+
Atoms: [
|
|
32
|
+
// [ASOR-INJECT:ATOM-DEFS(home)]
|
|
33
|
+
],
|
|
34
|
+
Organisms: [
|
|
35
|
+
// [ASOR-INJECT:ORGANISM-DEFS(home)]
|
|
36
|
+
],
|
|
37
|
+
} as IAsorRoute,
|
|
38
|
+
},
|
|
39
|
+
// [ASOR-INJECT:ROUTE-DEFS]
|
|
40
|
+
];
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { inject } from '@angular/core';
|
|
2
|
+
import {
|
|
3
|
+
StateService,
|
|
4
|
+
CacheInterceptor,
|
|
5
|
+
ErrorInterceptor,
|
|
6
|
+
ConsoleLogsConfig,
|
|
7
|
+
AuthGuard,
|
|
8
|
+
NotifyErrorService,
|
|
9
|
+
HttpRequestHandler,
|
|
10
|
+
LogLevel,
|
|
11
|
+
MockOrchestratorService,
|
|
12
|
+
AsorStorage,
|
|
13
|
+
} from '@asor-studio/asor-core';
|
|
14
|
+
import { AppConfig } from './app.config';
|
|
15
|
+
import { AppCacheConfig } from './app-cache.config';
|
|
16
|
+
import { AppStateCreateSystemDataSet } from './app-state.config';
|
|
17
|
+
import { PageHomeComponent } from '../pages/page-home/home.component';
|
|
18
|
+
// [ASOR-INJECT:LOG-IMPORTS]
|
|
19
|
+
|
|
20
|
+
export function initializeAsorCoreApp(
|
|
21
|
+
stateService: StateService,
|
|
22
|
+
mockOrchestratorService: MockOrchestratorService
|
|
23
|
+
) {
|
|
24
|
+
return () => {
|
|
25
|
+
const levels: LogLevel[] = ['INFO', 'WARNING', 'ERROR'];
|
|
26
|
+
|
|
27
|
+
ConsoleLogsConfig.silent = false;
|
|
28
|
+
ConsoleLogsConfig.defaultLevels = [];
|
|
29
|
+
|
|
30
|
+
ConsoleLogsConfig.setClassLevels(StateService.className, levels);
|
|
31
|
+
ConsoleLogsConfig.setClassLevels(AuthGuard.className, levels);
|
|
32
|
+
ConsoleLogsConfig.setClassLevels(CacheInterceptor.className, levels);
|
|
33
|
+
ConsoleLogsConfig.setClassLevels(ErrorInterceptor.className, levels);
|
|
34
|
+
ConsoleLogsConfig.setClassLevels(NotifyErrorService.className, levels);
|
|
35
|
+
ConsoleLogsConfig.setClassLevels(HttpRequestHandler.className, levels);
|
|
36
|
+
|
|
37
|
+
// Init Configs
|
|
38
|
+
ConsoleLogsConfig.setClassLevels(AppConfig.className, levels);
|
|
39
|
+
ConsoleLogsConfig.setClassLevels(AppCacheConfig.className, levels);
|
|
40
|
+
AppConfig.init();
|
|
41
|
+
AppCacheConfig.init();
|
|
42
|
+
|
|
43
|
+
// Register Pages (To enable BaseStorageComponent logs)
|
|
44
|
+
ConsoleLogsConfig.setClassLevels(PageHomeComponent.className, levels);
|
|
45
|
+
// [ASOR-INJECT:LOG-REGISTRATIONS]
|
|
46
|
+
|
|
47
|
+
stateService.initialize({
|
|
48
|
+
globalStateName: '<placeholder-globalStateName>',
|
|
49
|
+
encryptionType: AsorStorage.StateConst.EncryptType.AES,
|
|
50
|
+
nameType: AsorStorage.StateConst.Generate.AUTO,
|
|
51
|
+
keyType: AsorStorage.StateConst.Generate.AUTO,
|
|
52
|
+
asyncEnabled: true,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Register the Global State "AppSystemStatus" in memory
|
|
56
|
+
stateService.createDataSet(
|
|
57
|
+
AppStateCreateSystemDataSet.name,
|
|
58
|
+
AppStateCreateSystemDataSet.data,
|
|
59
|
+
AppStateCreateSystemDataSet.option!
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
return true;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ConfigCache, AsorGlobalEnum, ConsoleLogsUtility } from '@asor-studio/asor-core';
|
|
2
|
+
import { AppConfig } from './app.config';
|
|
3
|
+
|
|
4
|
+
export class AppCacheConfig extends ConfigCache {
|
|
5
|
+
public static readonly className: string = 'AppCacheConfig';
|
|
6
|
+
public static override globalStateName = '<placeholder-globalStateName>';
|
|
7
|
+
|
|
8
|
+
protected static override _pathsExtensions = [
|
|
9
|
+
{
|
|
10
|
+
pathValue: AppConfig.Cache.APP_BASE_I18N,
|
|
11
|
+
persistenceType: AsorGlobalEnum.CacheType.VOLATILE,
|
|
12
|
+
encriptType: AsorGlobalEnum.CacheEncriptType.NONE,
|
|
13
|
+
reqPayloadCache: false,
|
|
14
|
+
resctrictRoute: AppConfig.Route.NONE,
|
|
15
|
+
clearOn: [],
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
static init() {
|
|
20
|
+
ConsoleLogsUtility.info(AppCacheConfig, 'AppCacheConfig initialized');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static {
|
|
24
|
+
ConfigCache.SetConfiguration(AppCacheConfig);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AsorStorage, ICreateDataSet, IConnectDataSet } from '@asor-studio/asor-core';
|
|
2
|
+
import { IAppSystemStatus } from './interfaces/app-state.interfaces';
|
|
3
|
+
|
|
4
|
+
// Dataset Definition (Global data sitting next to the StateService)
|
|
5
|
+
export const AppStateCreateSystemDataSet: ICreateDataSet = {
|
|
6
|
+
name: 'app-system-status',
|
|
7
|
+
data: {
|
|
8
|
+
isMenuOpen: false,
|
|
9
|
+
appVersion: '1.0.0',
|
|
10
|
+
currentUser: null,
|
|
11
|
+
} as IAppSystemStatus,
|
|
12
|
+
option: {
|
|
13
|
+
storeType: AsorStorage.StateConst.StoreType.VOLATILE,
|
|
14
|
+
encrypt: false,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Connection Definition that components will use to subscribe to specific Proxy keys
|
|
19
|
+
export const AppStateConnectionSystem: IConnectDataSet = {
|
|
20
|
+
name: 'AppSystemConnection',
|
|
21
|
+
selectors: {
|
|
22
|
+
isMenuOpen: 'app-system-status.isMenuOpen',
|
|
23
|
+
appVersion: 'app-system-status.appVersion',
|
|
24
|
+
currentUser: 'app-system-status.currentUser',
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ConfigConst, ConsoleLogsUtility } from '@asor-studio/asor-core';
|
|
2
|
+
|
|
3
|
+
export class AppConfig extends ConfigConst {
|
|
4
|
+
public static readonly className: string = 'AppConfig';
|
|
5
|
+
|
|
6
|
+
static override BaseApi = '/api/v1';
|
|
7
|
+
static override SiteBaseUrl = '/';
|
|
8
|
+
static override SiteAssetsUrl = '/assets';
|
|
9
|
+
|
|
10
|
+
protected static override _routeExtensions = {
|
|
11
|
+
HOME: 'home',
|
|
12
|
+
// [ASOR-INJECT:ROUTE-EXTENSIONS]
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
protected static override _translationUrlExtensions = {
|
|
16
|
+
DefaultLanguage: 'en',
|
|
17
|
+
HOME: '/page-home',
|
|
18
|
+
SAMPLE_WIDGET: '/molecule-sample-widget',
|
|
19
|
+
// [ASOR-INJECT:TRANSLATION-EXTENSIONS]
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
protected static override _authCheckExtensions = {
|
|
23
|
+
HOME: 'home',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
protected static override _urlExtensions = {
|
|
27
|
+
HOME: '/home',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
protected static override _cacheExtensions = {
|
|
31
|
+
APP_BASE_I18N: 'i18n/app',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
protected static _assetsExtensions = {};
|
|
35
|
+
|
|
36
|
+
static override get Route() {
|
|
37
|
+
return { ...super.Route, ...this._routeExtensions };
|
|
38
|
+
}
|
|
39
|
+
static override get TranslationUrl() {
|
|
40
|
+
return { ...super.TranslationUrl, ...this._translationUrlExtensions };
|
|
41
|
+
}
|
|
42
|
+
static override get AuthCheck() {
|
|
43
|
+
return { ...super.AuthCheck, ...this._authCheckExtensions };
|
|
44
|
+
}
|
|
45
|
+
static override get Url() {
|
|
46
|
+
return { ...super.Url, ...this._urlExtensions };
|
|
47
|
+
}
|
|
48
|
+
static override get Cache() {
|
|
49
|
+
return { ...super.Cache, ...this._cacheExtensions };
|
|
50
|
+
}
|
|
51
|
+
static get Assets() {
|
|
52
|
+
return { ...this._assetsExtensions };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static init() {
|
|
56
|
+
ConsoleLogsUtility.info(AppConfig, 'AppConfig initialized');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static {
|
|
60
|
+
ConfigConst.SetConfiguration(AppConfig);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
/*
|
|
3
|
+
* IMPORTANT:
|
|
4
|
+
* This CSS block is only a minimal base generated by the template.
|
|
5
|
+
* In a real project, styles should be moved to a dedicated file
|
|
6
|
+
* based on the standard chosen by the team: CSS, SCSS, Sass, Less,
|
|
7
|
+
* or handled through global styles, utility classes, a design system, or inline styles.
|
|
8
|
+
*/
|
|
9
|
+
.sample-widget {
|
|
10
|
+
position: relative;
|
|
11
|
+
display: grid;
|
|
12
|
+
gap: 0.85rem;
|
|
13
|
+
padding: 0.95rem 1rem;
|
|
14
|
+
border: 1px solid rgba(226, 232, 240, 0.95);
|
|
15
|
+
border-radius: 1.25rem;
|
|
16
|
+
background:
|
|
17
|
+
radial-gradient(circle at top right, rgba(219, 39, 119, 0.08), transparent 40%),
|
|
18
|
+
linear-gradient(180deg, #ffffff, #fbfbff);
|
|
19
|
+
color: #0f172a;
|
|
20
|
+
box-shadow: 0 0.75rem 1.5rem rgba(15, 23, 42, 0.05);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.sample-widget--highlighted {
|
|
24
|
+
animation: sample-widget-pulse 780ms ease;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.sample-widget__title,
|
|
28
|
+
.sample-widget__text,
|
|
29
|
+
.sample-widget__status {
|
|
30
|
+
margin: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.sample-widget__title {
|
|
34
|
+
font-size: 0.98rem;
|
|
35
|
+
letter-spacing: 0.04em;
|
|
36
|
+
color: #7c3aed;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.sample-widget__text,
|
|
40
|
+
.sample-widget__status {
|
|
41
|
+
color: #475569;
|
|
42
|
+
font-size: 0.9rem;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.sample-widget__status-value {
|
|
46
|
+
font-weight: 600;
|
|
47
|
+
color: #64748b;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.sample-widget__status-value.active {
|
|
51
|
+
color: #db2777;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@keyframes sample-widget-pulse {
|
|
55
|
+
0%,
|
|
56
|
+
100% {
|
|
57
|
+
box-shadow: 0 0.75rem 1.5rem rgba(15, 23, 42, 0.05);
|
|
58
|
+
border-color: rgba(226, 232, 240, 0.95);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
35% {
|
|
62
|
+
box-shadow: 0 0 0 0.28rem rgba(168, 85, 247, 0.12), 0 1rem 2rem rgba(168, 85, 247, 0.18);
|
|
63
|
+
border-color: rgba(168, 85, 247, 0.45);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
60% {
|
|
67
|
+
box-shadow: 0 0 0 0.28rem rgba(236, 72, 153, 0.1), 0 1rem 2rem rgba(236, 72, 153, 0.16);
|
|
68
|
+
border-color: rgba(236, 72, 153, 0.4);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
</style>
|
|
72
|
+
|
|
73
|
+
<section
|
|
74
|
+
class="sample-widget"
|
|
75
|
+
[class.sample-widget--highlighted]="isHighlighted">
|
|
76
|
+
<h3 class="sample-widget__title">{{ widgetTitle }}</h3>
|
|
77
|
+
<p class="sample-widget__text">{{ 'SAMPLE_WIDGET.RESPONSIVE' | translate }}</p>
|
|
78
|
+
<p class="sample-widget__status">
|
|
79
|
+
{{ 'SAMPLE_WIDGET.MENU_STATUS' | translate }}:
|
|
80
|
+
<span class="sample-widget__status-value" [class.active]="isMenuOpen">
|
|
81
|
+
{{ (isMenuOpen ? 'SAMPLE_WIDGET.OPEN' : 'SAMPLE_WIDGET.CLOSED') | translate }}
|
|
82
|
+
</span>
|
|
83
|
+
</p>
|
|
84
|
+
</section>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { BaseStorageMolecule, TranslatePipe } from '@asor-studio/asor-core';
|
|
4
|
+
import { IAppSystemStatus } from '../../config/interfaces/app-state.interfaces';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'app-sample-widget',
|
|
8
|
+
standalone: true,
|
|
9
|
+
imports: [CommonModule, TranslatePipe],
|
|
10
|
+
templateUrl: './sample-widget.molecule.html',
|
|
11
|
+
})
|
|
12
|
+
export class SampleWidgetMolecule extends BaseStorageMolecule<IAppSystemStatus> implements OnInit, OnChanges {
|
|
13
|
+
public static override readonly className: string = 'SampleWidgetMolecule';
|
|
14
|
+
|
|
15
|
+
@Input() widgetTitle: string = 'Sample Widget';
|
|
16
|
+
@Input() highlightToken: number = 0;
|
|
17
|
+
public isHighlighted: boolean = false;
|
|
18
|
+
private highlightTimeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
19
|
+
|
|
20
|
+
constructor() {
|
|
21
|
+
super();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override ngOnInit(): void {
|
|
25
|
+
super.ngOnInit?.();
|
|
26
|
+
// Widget initialization logic
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
30
|
+
if (changes['highlightToken'] && !changes['highlightToken'].firstChange) {
|
|
31
|
+
this.isHighlighted = false;
|
|
32
|
+
|
|
33
|
+
if (this.highlightTimeoutId) {
|
|
34
|
+
clearTimeout(this.highlightTimeoutId);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
setTimeout(() => {
|
|
38
|
+
this.isHighlighted = true;
|
|
39
|
+
|
|
40
|
+
this.highlightTimeoutId = setTimeout(() => {
|
|
41
|
+
this.isHighlighted = false;
|
|
42
|
+
this.highlightTimeoutId = null;
|
|
43
|
+
}, 820);
|
|
44
|
+
}, 0);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
override baseMoleculeViewWillEnter(): void {
|
|
49
|
+
super.baseMoleculeViewWillEnter?.();
|
|
50
|
+
// Widget post-view initialization, highly suggested for complex widgets
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public get isMenuOpen(): boolean {
|
|
54
|
+
return this.props?.isMenuOpen || false;
|
|
55
|
+
}
|
|
56
|
+
}
|