@igo2/sdg-core 1.0.0-next.100
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/README.md +1 -0
- package/analytics/analytics.interface.d.ts +8 -0
- package/analytics/analytics.provider.d.ts +3 -0
- package/analytics/google-analytics/google-analytics.interface.d.ts +10 -0
- package/analytics/google-analytics/google-analytics.provider.d.ts +3 -0
- package/analytics/google-analytics/google-analytics.service.d.ts +12 -0
- package/analytics/google-analytics/index.d.ts +3 -0
- package/analytics/index.d.ts +3 -0
- package/fesm2022/igo2-sdg-core.mjs +189 -0
- package/fesm2022/igo2-sdg-core.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/layout/breakpoint/breakpoint.service.d.ts +12 -0
- package/layout/breakpoint/index.d.ts +1 -0
- package/layout/index.d.ts +1 -0
- package/package.json +37 -0
- package/public-api.d.ts +3 -0
- package/router/index.d.ts +4 -0
- package/router/route.interface.d.ts +9 -0
- package/router/route.utils.d.ts +2 -0
- package/router/router.d.ts +5 -0
- package/router/title-resolver/index.d.ts +2 -0
- package/router/title-resolver/title-resolver.d.ts +5 -0
- package/router/title-resolver/title-resolver.pipe.d.ts +11 -0
- package/src/_index.scss +4 -0
- package/src/layout/_breakpoints.scss +116 -0
- package/src/layout/_index.scss +1 -0
- package/src/layout/bootstrap-layout.scss +1067 -0
- package/src/style/_elevation.scss +54 -0
- package/src/style/_index.scss +4 -0
- package/src/style/_sass-utils.scss +24 -0
- package/src/style/_typography-utils.scss +23 -0
- package/src/style/_typography.scss +139 -0
- package/src/style/overrides/_index.scss +2 -0
- package/src/style/overrides/igo2-lib/_index.scss +9 -0
- package/src/style/overrides/igo2-lib/_list.scss +22 -0
- package/src/style/overrides/igo2-lib/_panel.scss +7 -0
- package/src/style/overrides/igo2-lib/_search-bar.scss +70 -0
- package/src/style/overrides/material/_button.scss +118 -0
- package/src/style/overrides/material/_checkbox.scss +120 -0
- package/src/style/overrides/material/_chip.scss +122 -0
- package/src/style/overrides/material/_dialog.scss +37 -0
- package/src/style/overrides/material/_divider.scss +11 -0
- package/src/style/overrides/material/_form-field.scss +20 -0
- package/src/style/overrides/material/_icon.scss +34 -0
- package/src/style/overrides/material/_index.scss +25 -0
- package/src/style/overrides/material/_input.scss +5 -0
- package/src/style/overrides/material/_radio-button.scss +124 -0
- package/src/style/overrides/material/_sidenav.scss +9 -0
- package/src/style/overrides/material/_tab.scss +95 -0
- package/src/theme/_index.scss +1 -0
- package/src/theme/material/_index.scss +1 -0
- package/src/theme/material/_theme.scss +241 -0
- package/src/tokens/_index.scss +7 -0
- package/src/tokens/_sys-colors.scss +99 -0
- package/src/tokens/_sys-elevation.scss +17 -0
- package/src/tokens/_sys-layout.scss +28 -0
- package/src/tokens/_sys-palettes.scss +72 -0
- package/src/tokens/_sys-typography.scss +109 -0
- package/src/tokens/_system.scss +56 -0
- package/src/tokens/_token-utils.scss +79 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Core
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EnvironmentProviders, Provider } from '@angular/core';
|
|
2
|
+
export interface AnalyticsFeature<KindT extends AnalyticsFeatureKind> {
|
|
3
|
+
kind: KindT;
|
|
4
|
+
providers: (Provider | EnvironmentProviders)[];
|
|
5
|
+
}
|
|
6
|
+
export declare enum AnalyticsFeatureKind {
|
|
7
|
+
GoogleAnalytic = 0
|
|
8
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface IGoogleAnalyticsOptions {
|
|
2
|
+
targetId: string;
|
|
3
|
+
/**
|
|
4
|
+
* See the config options https://developers.google.com/analytics/devguides/collection/ga4/reference/config
|
|
5
|
+
* By default we set:
|
|
6
|
+
* - send_page_view to false
|
|
7
|
+
* - cookie_flags to SameSite=None;Secure
|
|
8
|
+
**/
|
|
9
|
+
config?: Record<string, unknown>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { AnalyticsFeature, AnalyticsFeatureKind } from '../analytics.interface';
|
|
2
|
+
import { IGoogleAnalyticsOptions } from './google-analytics.interface';
|
|
3
|
+
export declare function withGoogleAnalytics(options: IGoogleAnalyticsOptions): AnalyticsFeature<AnalyticsFeatureKind.GoogleAnalytic>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Router } from '@angular/router';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export declare class GoogleAnalyticsService {
|
|
4
|
+
private router;
|
|
5
|
+
private routerEvents$$?;
|
|
6
|
+
constructor(router: Router);
|
|
7
|
+
initialize(): void;
|
|
8
|
+
trackEvent(eventName: string, eventParams: Record<string, unknown>): void;
|
|
9
|
+
trackFirstPageView(): void;
|
|
10
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<GoogleAnalyticsService, never>;
|
|
11
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<GoogleAnalyticsService>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { makeEnvironmentProviders, Injectable, provideAppInitializer, inject, PLATFORM_ID, signal, Optional, Pipe } from '@angular/core';
|
|
3
|
+
import { isPlatformServer, DOCUMENT } from '@angular/common';
|
|
4
|
+
import * as i1 from '@angular/router';
|
|
5
|
+
import { NavigationEnd } from '@angular/router';
|
|
6
|
+
import { filter, first } from 'rxjs';
|
|
7
|
+
import * as i1$1 from '@angular/cdk/layout';
|
|
8
|
+
|
|
9
|
+
var AnalyticsFeatureKind;
|
|
10
|
+
(function (AnalyticsFeatureKind) {
|
|
11
|
+
AnalyticsFeatureKind[AnalyticsFeatureKind["GoogleAnalytic"] = 0] = "GoogleAnalytic";
|
|
12
|
+
})(AnalyticsFeatureKind || (AnalyticsFeatureKind = {}));
|
|
13
|
+
|
|
14
|
+
function provideAnalytics(...features) {
|
|
15
|
+
const providers = [];
|
|
16
|
+
for (const feature of features) {
|
|
17
|
+
providers.push(...feature.providers);
|
|
18
|
+
}
|
|
19
|
+
return makeEnvironmentProviders(providers);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class GoogleAnalyticsService {
|
|
23
|
+
router;
|
|
24
|
+
routerEvents$$;
|
|
25
|
+
constructor(router) {
|
|
26
|
+
this.router = router;
|
|
27
|
+
}
|
|
28
|
+
initialize() {
|
|
29
|
+
if (!gtag) {
|
|
30
|
+
throw new Error('The gtag was not created for Google Analytics');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
trackEvent(eventName, eventParams) {
|
|
34
|
+
gtag('event', eventName, eventParams);
|
|
35
|
+
}
|
|
36
|
+
trackFirstPageView() {
|
|
37
|
+
if (this.routerEvents$$) {
|
|
38
|
+
throw new Error('Page tracking is already instantiated for Google Analytics');
|
|
39
|
+
}
|
|
40
|
+
this.routerEvents$$ = this.router.events
|
|
41
|
+
.pipe(filter((event) => event instanceof NavigationEnd), first())
|
|
42
|
+
.subscribe((event) => {
|
|
43
|
+
gtag('event', 'page_view', {
|
|
44
|
+
page_path: event.urlAfterRedirects
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: GoogleAnalyticsService, deps: [{ token: i1.Router }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
49
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: GoogleAnalyticsService, providedIn: 'root' });
|
|
50
|
+
}
|
|
51
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: GoogleAnalyticsService, decorators: [{
|
|
52
|
+
type: Injectable,
|
|
53
|
+
args: [{
|
|
54
|
+
providedIn: 'root'
|
|
55
|
+
}]
|
|
56
|
+
}], ctorParameters: () => [{ type: i1.Router }] });
|
|
57
|
+
|
|
58
|
+
function withGoogleAnalytics(options) {
|
|
59
|
+
if (!options.targetId) {
|
|
60
|
+
throw new Error('Vous devez configurer le targetId pour Google Analytics');
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
kind: AnalyticsFeatureKind.GoogleAnalytic,
|
|
64
|
+
providers: [
|
|
65
|
+
GoogleAnalyticsService,
|
|
66
|
+
provideAppInitializer(() => {
|
|
67
|
+
const platformId = inject(PLATFORM_ID);
|
|
68
|
+
if (isPlatformServer(platformId)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const document = inject(DOCUMENT);
|
|
72
|
+
const gaService = inject(GoogleAnalyticsService);
|
|
73
|
+
return googleAnalyticsFactory(document, gaService, options);
|
|
74
|
+
})
|
|
75
|
+
]
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function googleAnalyticsFactory(document, gaService, options) {
|
|
79
|
+
// Dynamically load the Google Analytics script
|
|
80
|
+
const script = document.createElement('script');
|
|
81
|
+
script.async = true;
|
|
82
|
+
script.src = `https://www.googletagmanager.com/gtag/js?id=${options.targetId}`;
|
|
83
|
+
document.head.appendChild(script);
|
|
84
|
+
script.onload = () => {
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
86
|
+
const _window = window;
|
|
87
|
+
_window['dataLayer'] = _window['dataLayer'] || [];
|
|
88
|
+
_window['gtag'] = function () {
|
|
89
|
+
// eslint-disable-next-line prefer-rest-params
|
|
90
|
+
_window['dataLayer'].push(arguments);
|
|
91
|
+
};
|
|
92
|
+
gtag('js', new Date());
|
|
93
|
+
// Disable automatic page view tracking
|
|
94
|
+
gtag('config', options.targetId, {
|
|
95
|
+
send_page_view: false,
|
|
96
|
+
cookie_flags: 'SameSite=None;Secure',
|
|
97
|
+
...(options.config ?? {})
|
|
98
|
+
});
|
|
99
|
+
gaService.initialize();
|
|
100
|
+
/**
|
|
101
|
+
* Track the first page view but after we fallback on the default TagManager event. You can manage this event in the TagManger admin console.
|
|
102
|
+
* https://support.google.com/tagmanager/answer/7679319?hl=en&ref_topic=7679108&sjid=1071553345249084852-NA
|
|
103
|
+
*/
|
|
104
|
+
gaService.trackFirstPageView();
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
class BreakpointService {
|
|
109
|
+
breakpointObserver;
|
|
110
|
+
_isHandset = signal(false);
|
|
111
|
+
get isHandset() {
|
|
112
|
+
return this._isHandset.asReadonly();
|
|
113
|
+
}
|
|
114
|
+
constructor(breakpointObserver) {
|
|
115
|
+
this.breakpointObserver = breakpointObserver;
|
|
116
|
+
this.handleBreakpoint();
|
|
117
|
+
}
|
|
118
|
+
handleBreakpoint() {
|
|
119
|
+
this.breakpointObserver
|
|
120
|
+
.observe('(max-width: 575px)')
|
|
121
|
+
.subscribe((result) => {
|
|
122
|
+
this._isHandset.set(result.matches);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: BreakpointService, deps: [{ token: i1$1.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
126
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: BreakpointService, providedIn: 'root' });
|
|
127
|
+
}
|
|
128
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: BreakpointService, decorators: [{
|
|
129
|
+
type: Injectable,
|
|
130
|
+
args: [{
|
|
131
|
+
providedIn: 'root'
|
|
132
|
+
}]
|
|
133
|
+
}], ctorParameters: () => [{ type: i1$1.BreakpointObserver }] });
|
|
134
|
+
|
|
135
|
+
const RouteTitleKey = 'RouteTitle';
|
|
136
|
+
const RouteTranslateKey = 'TranslateKey';
|
|
137
|
+
function hasStaticTitle(config) {
|
|
138
|
+
return typeof config.title === 'string' || config.title === null;
|
|
139
|
+
}
|
|
140
|
+
function resolveTitle(config, titleResolver) {
|
|
141
|
+
if (hasStaticTitle(config)) {
|
|
142
|
+
return config.title;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
return (titleResolver?.resolveStatic(config) ?? config.data?.[RouteTranslateKey] // try to fallback on the translation key
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
class TitleResolver {
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
class TitleResolverPipe {
|
|
154
|
+
titleResolver;
|
|
155
|
+
constructor(titleResolver) {
|
|
156
|
+
this.titleResolver = titleResolver;
|
|
157
|
+
}
|
|
158
|
+
transform(value) {
|
|
159
|
+
return resolveTitle(value, this.titleResolver);
|
|
160
|
+
}
|
|
161
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: TitleResolverPipe, deps: [{ token: TitleResolver, optional: true }], target: i0.ɵɵFactoryTarget.Pipe });
|
|
162
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.15", ngImport: i0, type: TitleResolverPipe, isStandalone: true, name: "titleResolver" });
|
|
163
|
+
}
|
|
164
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: TitleResolverPipe, decorators: [{
|
|
165
|
+
type: Pipe,
|
|
166
|
+
args: [{
|
|
167
|
+
name: 'titleResolver',
|
|
168
|
+
standalone: true
|
|
169
|
+
}]
|
|
170
|
+
}], ctorParameters: () => [{ type: TitleResolver, decorators: [{
|
|
171
|
+
type: Optional
|
|
172
|
+
}] }] });
|
|
173
|
+
|
|
174
|
+
function pathIsExternal(path) {
|
|
175
|
+
const regex = /^https?:\/\//;
|
|
176
|
+
return regex.test(path);
|
|
177
|
+
}
|
|
178
|
+
function isSafeUrl(url) {
|
|
179
|
+
const safePattern = /^(https?:\/\/|\/(?!\/)|\.\/|\.\.\/)/;
|
|
180
|
+
const unsafePattern = /^(javascript:|data:|vbscript:)/i;
|
|
181
|
+
return safePattern.test(url) && !unsafePattern.test(url.trim());
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Generated bundle index. Do not edit.
|
|
186
|
+
*/
|
|
187
|
+
|
|
188
|
+
export { AnalyticsFeatureKind, BreakpointService, GoogleAnalyticsService, RouteTitleKey, RouteTranslateKey, TitleResolver, TitleResolverPipe, isSafeUrl, pathIsExternal, provideAnalytics, resolveTitle, withGoogleAnalytics };
|
|
189
|
+
//# sourceMappingURL=igo2-sdg-core.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"igo2-sdg-core.mjs","sources":["../../../packages/core/src/analytics/analytics.interface.ts","../../../packages/core/src/analytics/analytics.provider.ts","../../../packages/core/src/analytics/google-analytics/google-analytics.service.ts","../../../packages/core/src/analytics/google-analytics/google-analytics.provider.ts","../../../packages/core/src/layout/breakpoint/breakpoint.service.ts","../../../packages/core/src/router/router.ts","../../../packages/core/src/router/title-resolver/title-resolver.ts","../../../packages/core/src/router/title-resolver/title-resolver.pipe.ts","../../../packages/core/src/router/route.utils.ts","../../../packages/core/src/igo2-sdg-core.ts"],"sourcesContent":["import { EnvironmentProviders, Provider } from '@angular/core';\n\nexport interface AnalyticsFeature<KindT extends AnalyticsFeatureKind> {\n kind: KindT;\n providers: (Provider | EnvironmentProviders)[];\n}\n\nexport enum AnalyticsFeatureKind {\n GoogleAnalytic = 0\n}\n","import {\n EnvironmentProviders,\n Provider,\n makeEnvironmentProviders\n} from '@angular/core';\n\nimport { AnalyticsFeature, AnalyticsFeatureKind } from './analytics.interface';\n\nexport function provideAnalytics(\n ...features: AnalyticsFeature<AnalyticsFeatureKind>[]\n) {\n const providers: (Provider | EnvironmentProviders)[] = [];\n\n for (const feature of features) {\n providers.push(...feature.providers);\n }\n\n return makeEnvironmentProviders(providers);\n}\n","import { Injectable } from '@angular/core';\nimport { NavigationEnd, Router } from '@angular/router';\n\nimport { Subscription, filter, first } from 'rxjs';\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\ndeclare let gtag: Function;\n\n@Injectable({\n providedIn: 'root'\n})\nexport class GoogleAnalyticsService {\n private routerEvents$$?: Subscription;\n\n constructor(private router: Router) {}\n\n initialize(): void {\n if (!gtag) {\n throw new Error('The gtag was not created for Google Analytics');\n }\n }\n\n trackEvent(eventName: string, eventParams: Record<string, unknown>): void {\n gtag('event', eventName, eventParams);\n }\n\n trackFirstPageView(): void {\n if (this.routerEvents$$) {\n throw new Error(\n 'Page tracking is already instantiated for Google Analytics'\n );\n }\n\n this.routerEvents$$ = this.router.events\n .pipe(\n filter((event) => event instanceof NavigationEnd),\n first()\n )\n .subscribe((event: NavigationEnd) => {\n gtag!('event', 'page_view', {\n page_path: event.urlAfterRedirects\n });\n });\n }\n}\n","import { DOCUMENT, isPlatformServer } from '@angular/common';\nimport { PLATFORM_ID, inject, provideAppInitializer } from '@angular/core';\n\nimport { AnalyticsFeature, AnalyticsFeatureKind } from '../analytics.interface';\nimport { IGoogleAnalyticsOptions } from './google-analytics.interface';\nimport { GoogleAnalyticsService } from './google-analytics.service';\n\nexport function withGoogleAnalytics(\n options: IGoogleAnalyticsOptions\n): AnalyticsFeature<AnalyticsFeatureKind.GoogleAnalytic> {\n if (!options.targetId) {\n throw new Error('Vous devez configurer le targetId pour Google Analytics');\n }\n\n return {\n kind: AnalyticsFeatureKind.GoogleAnalytic,\n providers: [\n GoogleAnalyticsService,\n provideAppInitializer(() => {\n const platformId = inject(PLATFORM_ID);\n if (isPlatformServer(platformId)) {\n return;\n }\n\n const document = inject(DOCUMENT);\n const gaService = inject(GoogleAnalyticsService);\n return googleAnalyticsFactory(document, gaService, options);\n })\n ]\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\ndeclare let gtag: Function;\n\nfunction googleAnalyticsFactory(\n document: Document,\n gaService: GoogleAnalyticsService,\n options: IGoogleAnalyticsOptions\n): void {\n // Dynamically load the Google Analytics script\n const script = document.createElement('script');\n script.async = true;\n script.src = `https://www.googletagmanager.com/gtag/js?id=${options.targetId}`;\n document.head.appendChild(script);\n\n script.onload = () => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const _window = window as any;\n _window['dataLayer'] = _window['dataLayer'] || [];\n _window['gtag'] = function () {\n // eslint-disable-next-line prefer-rest-params\n _window['dataLayer'].push(arguments);\n };\n\n gtag('js', new Date());\n\n // Disable automatic page view tracking\n gtag('config', options.targetId, {\n send_page_view: false,\n cookie_flags: 'SameSite=None;Secure',\n ...(options.config ?? {})\n });\n\n gaService.initialize();\n\n /**\n * Track the first page view but after we fallback on the default TagManager event. You can manage this event in the TagManger admin console.\n * https://support.google.com/tagmanager/answer/7679319?hl=en&ref_topic=7679108&sjid=1071553345249084852-NA\n */\n gaService.trackFirstPageView();\n };\n}\n","import { BreakpointObserver } from '@angular/cdk/layout';\nimport { Injectable, Signal, signal } from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class BreakpointService {\n private _isHandset = signal(false);\n\n get isHandset(): Signal<boolean> {\n return this._isHandset.asReadonly();\n }\n\n constructor(private breakpointObserver: BreakpointObserver) {\n this.handleBreakpoint();\n }\n\n private handleBreakpoint(): void {\n this.breakpointObserver\n .observe('(max-width: 575px)')\n .subscribe((result) => {\n this._isHandset.set(result.matches);\n });\n }\n}\n","import { Route } from '@angular/router';\n\nimport { TitleResolver } from './title-resolver/title-resolver';\n\nexport const RouteTitleKey = 'RouteTitle';\nexport const RouteTranslateKey = 'TranslateKey';\n\nfunction hasStaticTitle(config: Route): boolean {\n return typeof config.title === 'string' || config.title === null;\n}\n\nexport function resolveTitle(\n config: Route,\n titleResolver?: TitleResolver\n): string | undefined {\n if (hasStaticTitle(config)) {\n return config.title as string;\n } else {\n return (\n titleResolver?.resolveStatic(config) ?? config.data?.[RouteTranslateKey] // try to fallback on the translation key\n );\n }\n}\n","import {\n ActivatedRouteSnapshot,\n MaybeAsync,\n Resolve,\n Route,\n RouterStateSnapshot\n} from '@angular/router';\n\nexport abstract class TitleResolver<T = string> implements Resolve<T> {\n abstract resolve(\n route: ActivatedRouteSnapshot,\n state: RouterStateSnapshot\n ): MaybeAsync<T>;\n abstract resolveStatic(route: Route): string | undefined;\n}\n","import { Optional, Pipe, PipeTransform } from '@angular/core';\n\nimport { SdgRoute } from '../route.interface';\nimport { resolveTitle } from '../router';\nimport { TitleResolver } from './title-resolver';\n\n@Pipe({\n name: 'titleResolver',\n standalone: true\n})\nexport class TitleResolverPipe implements PipeTransform {\n constructor(@Optional() private titleResolver: TitleResolver) {}\n\n transform(value: SdgRoute): string | undefined {\n return resolveTitle(value, this.titleResolver);\n }\n}\n","export function pathIsExternal(path: string): boolean {\n const regex = /^https?:\\/\\//;\n return regex.test(path);\n}\n\nexport function isSafeUrl(url: string): boolean {\n const safePattern = /^(https?:\\/\\/|\\/(?!\\/)|\\.\\/|\\.\\.\\/)/;\n const unsafePattern = /^(javascript:|data:|vbscript:)/i;\n return safePattern.test(url) && !unsafePattern.test(url.trim());\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1","i1.TitleResolver"],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BreakpointObserver } from '@angular/cdk/layout';
|
|
2
|
+
import { Signal } from '@angular/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class BreakpointService {
|
|
5
|
+
private breakpointObserver;
|
|
6
|
+
private _isHandset;
|
|
7
|
+
get isHandset(): Signal<boolean>;
|
|
8
|
+
constructor(breakpointObserver: BreakpointObserver);
|
|
9
|
+
private handleBreakpoint;
|
|
10
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<BreakpointService, never>;
|
|
11
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<BreakpointService>;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './breakpoint.service';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './breakpoint';
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@igo2/sdg-core",
|
|
3
|
+
"version": "1.0.0-next.100",
|
|
4
|
+
"license": "LiLiQ-R",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/infra-geo-ouverte/sdg.git",
|
|
8
|
+
"directory": "packages/core"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"sass": "./src/_index.scss",
|
|
13
|
+
"types": "./index.d.ts",
|
|
14
|
+
"default": "./fesm2022/igo2-sdg-core.mjs"
|
|
15
|
+
},
|
|
16
|
+
"./layout": {
|
|
17
|
+
"sass": "./src/layout/bootstrap-layout.scss"
|
|
18
|
+
},
|
|
19
|
+
"./package.json": {
|
|
20
|
+
"default": "./package.json"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@angular/cdk": "^19.2.0",
|
|
25
|
+
"@angular/common": "^19.2.0",
|
|
26
|
+
"@angular/core": "^19.2.0",
|
|
27
|
+
"@angular/material": "^19.2.0",
|
|
28
|
+
"@angular/router": "^19.2.0",
|
|
29
|
+
"bootstrap": "^5.3.0"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"tslib": "^2.6.0"
|
|
33
|
+
},
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"module": "fesm2022/igo2-sdg-core.mjs",
|
|
36
|
+
"typings": "index.d.ts"
|
|
37
|
+
}
|
package/public-api.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Route } from '@angular/router';
|
|
2
|
+
export type SdgRoutes = SdgRoute[];
|
|
3
|
+
export interface SdgRoute extends Route {
|
|
4
|
+
isHome?: boolean;
|
|
5
|
+
description?: string;
|
|
6
|
+
children?: SdgRoutes;
|
|
7
|
+
/** Hidden in the primary tabs navigation and in the breadcrumbs */
|
|
8
|
+
hidden?: boolean;
|
|
9
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Route } from '@angular/router';
|
|
2
|
+
import { TitleResolver } from './title-resolver/title-resolver';
|
|
3
|
+
export declare const RouteTitleKey = "RouteTitle";
|
|
4
|
+
export declare const RouteTranslateKey = "TranslateKey";
|
|
5
|
+
export declare function resolveTitle(config: Route, titleResolver?: TitleResolver): string | undefined;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ActivatedRouteSnapshot, MaybeAsync, Resolve, Route, RouterStateSnapshot } from '@angular/router';
|
|
2
|
+
export declare abstract class TitleResolver<T = string> implements Resolve<T> {
|
|
3
|
+
abstract resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): MaybeAsync<T>;
|
|
4
|
+
abstract resolveStatic(route: Route): string | undefined;
|
|
5
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PipeTransform } from '@angular/core';
|
|
2
|
+
import { SdgRoute } from '../route.interface';
|
|
3
|
+
import { TitleResolver } from './title-resolver';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export declare class TitleResolverPipe implements PipeTransform {
|
|
6
|
+
private titleResolver;
|
|
7
|
+
constructor(titleResolver: TitleResolver);
|
|
8
|
+
transform(value: SdgRoute): string | undefined;
|
|
9
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TitleResolverPipe, [{ optional: true; }]>;
|
|
10
|
+
static ɵpipe: i0.ɵɵPipeDeclaration<TitleResolverPipe, "titleResolver", true>;
|
|
11
|
+
}
|
package/src/_index.scss
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
@use 'sass:map';
|
|
2
|
+
|
|
3
|
+
// https://design.quebec.ca/design/bases/grille-8px#c84016
|
|
4
|
+
$grids: (
|
|
5
|
+
sm: (
|
|
6
|
+
min-width: 0,
|
|
7
|
+
max-width: 575px,
|
|
8
|
+
container-max-width: container-max-width('mobile'),
|
|
9
|
+
columns: 4,
|
|
10
|
+
spacing: 16px,
|
|
11
|
+
margins: 8px
|
|
12
|
+
),
|
|
13
|
+
md: (
|
|
14
|
+
min-width: 576px,
|
|
15
|
+
max-width: 767px,
|
|
16
|
+
container-max-width: container-max-width('mobile-landscape'),
|
|
17
|
+
columns: 4,
|
|
18
|
+
spacing: 16px,
|
|
19
|
+
margins: 8px
|
|
20
|
+
),
|
|
21
|
+
lg: (
|
|
22
|
+
min-width: 768px,
|
|
23
|
+
max-width: 991px,
|
|
24
|
+
container-max-width: container-max-width('tablet'),
|
|
25
|
+
columns: 12,
|
|
26
|
+
spacing: 24px,
|
|
27
|
+
margins: 12px
|
|
28
|
+
),
|
|
29
|
+
xl: (
|
|
30
|
+
min-width: 992px,
|
|
31
|
+
max-width: 1199px,
|
|
32
|
+
container-max-width: container-max-width('laptop'),
|
|
33
|
+
columns: 12,
|
|
34
|
+
spacing: 24px,
|
|
35
|
+
margins: 12px
|
|
36
|
+
),
|
|
37
|
+
max: (
|
|
38
|
+
min-width: 1200px,
|
|
39
|
+
max-width: 9999px,
|
|
40
|
+
container-max-width: container-max-width('desktop'),
|
|
41
|
+
columns: 12,
|
|
42
|
+
spacing: 32px,
|
|
43
|
+
margins: 16px
|
|
44
|
+
)
|
|
45
|
+
) !default;
|
|
46
|
+
|
|
47
|
+
$devices: (
|
|
48
|
+
mobile: 'sm',
|
|
49
|
+
mobile-landscape: 'md',
|
|
50
|
+
tablet: 'lg',
|
|
51
|
+
laptop: 'xl',
|
|
52
|
+
desktop: 'max'
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Flattens a nested map, concatenating keys with '-' and returning a flat map.
|
|
56
|
+
@function get-grid-tokens() {
|
|
57
|
+
$result: ();
|
|
58
|
+
@each $breakpoint, $valueMap in $grids {
|
|
59
|
+
@each $key, $value in $valueMap {
|
|
60
|
+
$full-key: $key + '-' + $breakpoint;
|
|
61
|
+
$result: map.merge(
|
|
62
|
+
$result,
|
|
63
|
+
(
|
|
64
|
+
$full-key: $value
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
@return $result;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@function breakpoint($device) {
|
|
73
|
+
@return map.get($devices, $device);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@function min-width($device) {
|
|
77
|
+
$breakpoint: breakpoint($device);
|
|
78
|
+
@if $breakpoint {
|
|
79
|
+
@return map.get($grids, $breakpoint, min-width);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@function max-width($device) {
|
|
84
|
+
$breakpoint: breakpoint($device);
|
|
85
|
+
@if $breakpoint {
|
|
86
|
+
@return map.get($grids, $breakpoint, max-width);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@function container-max-width($device) {
|
|
91
|
+
$breakpoint: breakpoint($device);
|
|
92
|
+
$margins: map.get($grids, $breakpoint, margins);
|
|
93
|
+
|
|
94
|
+
@if $breakpoint == 'sm' {
|
|
95
|
+
@return calc(map.get($grids, $breakpoint, max-width) - 2 * $margins);
|
|
96
|
+
} @else {
|
|
97
|
+
@return calc(map.get($grids, $breakpoint, min-width) - 2 * $margins);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Media of at most the maximum breakpoint width. No query for the largest breakpoint.
|
|
102
|
+
// Makes the @content apply to the given breakpoint and narrower.
|
|
103
|
+
// https://github.com/twbs/bootstrap/blob/main/scss/mixins/_breakpoints.scss
|
|
104
|
+
@mixin media($device) {
|
|
105
|
+
$breakpoint: breakpoint($device);
|
|
106
|
+
@if $breakpoint {
|
|
107
|
+
$max-width: map.get($grids, $breakpoint, max-width);
|
|
108
|
+
@if $max-width {
|
|
109
|
+
@media (max-width: $max-width) {
|
|
110
|
+
@content;
|
|
111
|
+
}
|
|
112
|
+
} @else {
|
|
113
|
+
@content;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@forward './breakpoints';
|