@sumaris-net/ngx-components 18.14.2 → 18.14.4
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/esm2022/src/app/shared/rx-state/rx-state.decorators.mjs +64 -121
- package/esm2022/src/app/social/feed/feed.component.mjs +14 -21
- package/fesm2022/sumaris-net.ngx-components.mjs +76 -138
- package/fesm2022/sumaris-net.ngx-components.mjs.map +1 -1
- package/package.json +1 -1
- package/src/app/shared/inputs.d.ts +1 -1
- package/src/app/shared/rx-state/rx-state.decorators.d.ts +1 -17
- package/src/app/social/feed/feed.component.d.ts +8 -8
|
@@ -26365,22 +26365,16 @@ class DecoratorUtils {
|
|
|
26365
26365
|
static createPropertyName(prefix, propertyKey) {
|
|
26366
26366
|
return `${prefix}${this.capitalize(propertyKey)}`;
|
|
26367
26367
|
}
|
|
26368
|
-
static validateStateProperty(target,
|
|
26369
|
-
if (!production &&
|
|
26370
|
-
|
|
26371
|
-
if (!${stateVarName}) {
|
|
26372
|
-
throw new Error('Missing state! Please add a RxState in class: ' + this.constructor.name);
|
|
26368
|
+
static validateStateProperty(target, stateObject) {
|
|
26369
|
+
if (!production && !stateObject) {
|
|
26370
|
+
throw new Error(`Missing state! Please add a RxState in class: ${target.constructor.name}`);
|
|
26373
26371
|
}
|
|
26374
|
-
`;
|
|
26375
|
-
}
|
|
26376
|
-
return '';
|
|
26377
26372
|
}
|
|
26378
26373
|
}
|
|
26379
26374
|
const STATE_VAR_NAME_KEY = '__stateName';
|
|
26380
26375
|
const DEFAULT_STATE_VAR_NAME = '_state';
|
|
26381
26376
|
/**
|
|
26382
26377
|
* Decorator to register the RxState property in a component
|
|
26383
|
-
* Must be used once per class hierarchy
|
|
26384
26378
|
*/
|
|
26385
26379
|
function RxStateRegister() {
|
|
26386
26380
|
return function (target, key) {
|
|
@@ -26397,49 +26391,36 @@ function RxStateRegister() {
|
|
|
26397
26391
|
}
|
|
26398
26392
|
/**
|
|
26399
26393
|
* Decorator for RxState properties with getter/setter access
|
|
26400
|
-
* Creates reactive properties that sync with RxState
|
|
26401
26394
|
*/
|
|
26402
26395
|
function RxStateProperty(statePropertyName, projectValueReducer) {
|
|
26403
26396
|
return function (target, key) {
|
|
26404
|
-
// Vérification de type au runtime (optionnelle)
|
|
26405
|
-
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
26406
|
-
if (descriptor && typeof descriptor.value !== 'undefined') {
|
|
26407
|
-
// On peut ajouter ici des vérifications de type runtime si nécessaire
|
|
26408
|
-
}
|
|
26409
26397
|
const finalStatePropertyName = statePropertyName || key;
|
|
26410
26398
|
const stateVarName = target instanceof RxState ? null : target[STATE_VAR_NAME_KEY] || DEFAULT_STATE_VAR_NAME;
|
|
26411
|
-
|
|
26412
|
-
|
|
26413
|
-
const
|
|
26414
|
-
const setMethodName = DecoratorUtils.createMethodName('_set', key);
|
|
26415
|
-
const reducerMethodName = DecoratorUtils.createMethodName('_reduce', key);
|
|
26416
|
-
// State validation (only in development)
|
|
26417
|
-
const stateValidation = DecoratorUtils.validateStateProperty(target, stateObject);
|
|
26418
|
-
// Create reducer logic
|
|
26419
|
-
const reducerLogic = projectValueReducer ? `(state) => this.${reducerMethodName}(state, value)` : '() => value';
|
|
26420
|
-
// Create dynamic methods using Function constructor for better performance
|
|
26421
|
-
const getter = new Function(`
|
|
26422
|
-
return function ${getMethodName}() {
|
|
26423
|
-
${stateValidation}
|
|
26424
|
-
return ${stateObject}.get('${finalStatePropertyName}');
|
|
26425
|
-
}
|
|
26426
|
-
`)();
|
|
26427
|
-
const setter = new Function(`
|
|
26428
|
-
return function ${setMethodName}(value) {
|
|
26429
|
-
${stateValidation}
|
|
26430
|
-
${stateObject}.set('${finalStatePropertyName}', ${reducerLogic});
|
|
26431
|
-
}
|
|
26432
|
-
`)();
|
|
26433
|
-
// Attach methods to prototype
|
|
26434
|
-
target[getMethodName] = getter;
|
|
26435
|
-
target[setMethodName] = setter;
|
|
26436
|
-
if (projectValueReducer) {
|
|
26437
|
-
target[reducerMethodName] = projectValueReducer;
|
|
26438
|
-
}
|
|
26399
|
+
// Create unique property names to avoid conflicts
|
|
26400
|
+
const privateValueKey = `__${key}_value`;
|
|
26401
|
+
const privateInitializedKey = `__${key}_initialized`;
|
|
26439
26402
|
// Define property with getter/setter
|
|
26440
26403
|
Object.defineProperty(target, key, {
|
|
26441
|
-
get:
|
|
26442
|
-
|
|
26404
|
+
get: function () {
|
|
26405
|
+
const stateObject = stateVarName ? this[stateVarName] : this;
|
|
26406
|
+
DecoratorUtils.validateStateProperty(target, stateObject);
|
|
26407
|
+
if (!this[privateInitializedKey]) {
|
|
26408
|
+
this[privateValueKey] = stateObject.get(finalStatePropertyName);
|
|
26409
|
+
this[privateInitializedKey] = true;
|
|
26410
|
+
}
|
|
26411
|
+
return this[privateValueKey];
|
|
26412
|
+
},
|
|
26413
|
+
set: function (value) {
|
|
26414
|
+
const stateObject = stateVarName ? this[stateVarName] : this;
|
|
26415
|
+
DecoratorUtils.validateStateProperty(target, stateObject);
|
|
26416
|
+
this[privateValueKey] = value;
|
|
26417
|
+
if (projectValueReducer) {
|
|
26418
|
+
stateObject.set(finalStatePropertyName, (state) => projectValueReducer(state, value));
|
|
26419
|
+
}
|
|
26420
|
+
else {
|
|
26421
|
+
stateObject.set(finalStatePropertyName, () => value);
|
|
26422
|
+
}
|
|
26423
|
+
},
|
|
26443
26424
|
enumerable: true,
|
|
26444
26425
|
configurable: true,
|
|
26445
26426
|
});
|
|
@@ -26451,117 +26432,79 @@ function RxStateProperty(statePropertyName, projectValueReducer) {
|
|
|
26451
26432
|
}
|
|
26452
26433
|
/**
|
|
26453
26434
|
* Decorator for RxState observable selectors
|
|
26454
|
-
* Creates observable properties that select from RxState
|
|
26455
|
-
*
|
|
26456
|
-
* ⚠️ IMPORTANT: La propriété décorée DOIT être typée comme Observable<T>
|
|
26457
|
-
*
|
|
26458
|
-
* @example
|
|
26459
|
-
* ```typescript
|
|
26460
|
-
* @RxStateSelect()
|
|
26461
|
-
* protected pmfms$: Observable<IPmfm[]>; // ✅ Correct
|
|
26462
|
-
*
|
|
26463
|
-
* @RxStateSelect()
|
|
26464
|
-
* protected badProperty: boolean; // ❌ TypeScript Error
|
|
26465
|
-
* ```
|
|
26466
26435
|
*/
|
|
26467
26436
|
function RxStateSelect(statePropertyName, opts) {
|
|
26468
26437
|
return function (target, key) {
|
|
26469
|
-
//
|
|
26438
|
+
// Convention check
|
|
26470
26439
|
if (!production && !key.endsWith('$')) {
|
|
26471
26440
|
console.warn(`[RxStateSelect] Convention: Property ${target.constructor?.name}.${key} should end with '$' to indicate it's an Observable`);
|
|
26472
26441
|
}
|
|
26473
|
-
// Determine state property name
|
|
26442
|
+
// Determine state property name
|
|
26474
26443
|
const finalStatePropertyName = statePropertyName || key.replace(/\$$/, '');
|
|
26475
26444
|
// Determine state object
|
|
26476
26445
|
const stateVarName = target instanceof RxState ? null : target[STATE_VAR_NAME_KEY] || opts?.stateName || DEFAULT_STATE_VAR_NAME;
|
|
26477
|
-
const stateObject = stateVarName ? `this.${stateVarName}` : 'this';
|
|
26478
26446
|
// Create cache property name
|
|
26479
|
-
const cachePropertyName = `
|
|
26480
|
-
// Generate method name
|
|
26481
|
-
const getMethodName = DecoratorUtils.createMethodName('_get', key.replace(/\$$/, '') + '$');
|
|
26482
|
-
// Create observable selector logic
|
|
26483
|
-
const observableSelector = finalStatePropertyName === '$'
|
|
26484
|
-
? `${stateObject}.$`
|
|
26485
|
-
: finalStatePropertyName.includes('.')
|
|
26486
|
-
? `${stateObject}.select('${finalStatePropertyName.split('.').join("', '")}')`
|
|
26487
|
-
: `${stateObject}.select('${finalStatePropertyName}')`;
|
|
26488
|
-
// State validation
|
|
26489
|
-
const stateValidation = DecoratorUtils.validateStateProperty(target, stateObject);
|
|
26490
|
-
// Create getter with caching
|
|
26491
|
-
const getter = new Function(`
|
|
26492
|
-
return function ${getMethodName}() {
|
|
26493
|
-
${stateValidation}
|
|
26494
|
-
if (!this.${cachePropertyName}) {
|
|
26495
|
-
this.${cachePropertyName} = ${observableSelector};
|
|
26496
|
-
}
|
|
26497
|
-
return this.${cachePropertyName};
|
|
26498
|
-
}
|
|
26499
|
-
`)();
|
|
26500
|
-
// Attach method to prototype
|
|
26501
|
-
target[getMethodName] = getter;
|
|
26447
|
+
const cachePropertyName = `__${key}_cache`;
|
|
26502
26448
|
// Define property with getter only
|
|
26503
26449
|
Object.defineProperty(target, key, {
|
|
26504
|
-
get:
|
|
26450
|
+
get: function () {
|
|
26451
|
+
const stateObject = stateVarName ? this[stateVarName] : this;
|
|
26452
|
+
DecoratorUtils.validateStateProperty(target, stateObject);
|
|
26453
|
+
if (!this[cachePropertyName]) {
|
|
26454
|
+
if (finalStatePropertyName === '$') {
|
|
26455
|
+
this[cachePropertyName] = stateObject.$;
|
|
26456
|
+
}
|
|
26457
|
+
else if (finalStatePropertyName.includes('.')) {
|
|
26458
|
+
const path = finalStatePropertyName.split('.');
|
|
26459
|
+
this[cachePropertyName] = stateObject.select(...path);
|
|
26460
|
+
}
|
|
26461
|
+
else {
|
|
26462
|
+
this[cachePropertyName] = stateObject.select(finalStatePropertyName);
|
|
26463
|
+
}
|
|
26464
|
+
}
|
|
26465
|
+
return this[cachePropertyName];
|
|
26466
|
+
},
|
|
26505
26467
|
enumerable: true,
|
|
26506
26468
|
configurable: false,
|
|
26507
26469
|
});
|
|
26508
26470
|
// Development logging
|
|
26509
26471
|
if (!production) {
|
|
26510
|
-
console.debug(`[RxStateSelect] ${target.constructor?.name}.${key} -> ${
|
|
26472
|
+
console.debug(`[RxStateSelect] ${target.constructor?.name}.${key} -> state.select('${finalStatePropertyName}')`);
|
|
26511
26473
|
}
|
|
26512
26474
|
};
|
|
26513
26475
|
}
|
|
26514
26476
|
/**
|
|
26515
26477
|
* Utility decorator to create computed observables from state
|
|
26516
|
-
*
|
|
26517
|
-
* ⚠️ IMPORTANT: La propriété décorée DOIT être typée comme Observable<T>
|
|
26518
26478
|
*/
|
|
26519
26479
|
function RxStateComputed(dependencies, computeFn, opts) {
|
|
26520
26480
|
return function (target, key) {
|
|
26521
|
-
//
|
|
26481
|
+
// Convention check
|
|
26522
26482
|
if (!production && !key.endsWith('$')) {
|
|
26523
26483
|
console.warn(`[RxStateComputed] Convention: Property ${target.constructor?.name}.${key} should end with '$' to indicate it's an Observable`);
|
|
26524
26484
|
}
|
|
26525
26485
|
const stateVarName = target instanceof RxState ? null : target[STATE_VAR_NAME_KEY] || opts?.stateName || DEFAULT_STATE_VAR_NAME;
|
|
26526
|
-
const
|
|
26527
|
-
const cachePropertyName = `_${key}`;
|
|
26528
|
-
const getMethodName = DecoratorUtils.createMethodName('_get', key.replace(/\$$/, '') + '$');
|
|
26529
|
-
const computeMethodName = DecoratorUtils.createMethodName('_compute', key);
|
|
26530
|
-
const keyCompareMapPropertyName = DecoratorUtils.createPropertyName(`_compareMap`, key);
|
|
26531
|
-
// State validation
|
|
26532
|
-
const stateValidation = DecoratorUtils.validateStateProperty(target, stateObject);
|
|
26533
|
-
// Create dependencies array as string for code generation
|
|
26534
|
-
const dependenciesStr = dependencies.map((dep) => `'${dep}'`).join(', ');
|
|
26535
|
-
// Create the compute method as string, for code generation
|
|
26536
|
-
const computeMethodNameStr = computeFn ? `, (slice) => this.${computeMethodName}(slice)` : '';
|
|
26537
|
-
// Create the comparator map function as string, for code generation
|
|
26538
|
-
const keyCompareMapStr = opts?.keyCompareMap ? `, this.${keyCompareMapPropertyName}` : '';
|
|
26539
|
-
// Create getter with caching using RxState's native multi-select + pipe(map())
|
|
26540
|
-
const getter = new Function(`
|
|
26541
|
-
return function ${getMethodName}() {
|
|
26542
|
-
${stateValidation}
|
|
26543
|
-
if (!this.${cachePropertyName}) {
|
|
26544
|
-
const { map } = require('rxjs/operators');
|
|
26545
|
-
this.${cachePropertyName} = ${stateObject}.select([${dependenciesStr}]${computeMethodNameStr}${keyCompareMapStr});
|
|
26546
|
-
}
|
|
26547
|
-
return this.${cachePropertyName};
|
|
26548
|
-
}
|
|
26549
|
-
`)();
|
|
26550
|
-
// Attach compute method, optional keyCompareMap with unique name, and getter to prototype
|
|
26551
|
-
if (computeFn)
|
|
26552
|
-
target[computeMethodName] = computeFn;
|
|
26553
|
-
if (opts?.keyCompareMap)
|
|
26554
|
-
target[keyCompareMapPropertyName] = opts.keyCompareMap;
|
|
26555
|
-
target[getMethodName] = getter;
|
|
26486
|
+
const cachePropertyName = `__${key}_cache`;
|
|
26556
26487
|
// Define property with getter only
|
|
26557
26488
|
Object.defineProperty(target, key, {
|
|
26558
|
-
get:
|
|
26489
|
+
get: function () {
|
|
26490
|
+
const stateObject = stateVarName ? this[stateVarName] : this;
|
|
26491
|
+
DecoratorUtils.validateStateProperty(target, stateObject);
|
|
26492
|
+
if (!this[cachePropertyName]) {
|
|
26493
|
+
let observable = stateObject.select(dependencies, opts?.keyCompareMap);
|
|
26494
|
+
if (computeFn) {
|
|
26495
|
+
const { map } = require('rxjs/operators');
|
|
26496
|
+
observable = observable.pipe(map(computeFn));
|
|
26497
|
+
}
|
|
26498
|
+
this[cachePropertyName] = observable;
|
|
26499
|
+
}
|
|
26500
|
+
return this[cachePropertyName];
|
|
26501
|
+
},
|
|
26559
26502
|
enumerable: true,
|
|
26560
26503
|
configurable: false,
|
|
26561
26504
|
});
|
|
26562
26505
|
// Development logging
|
|
26563
26506
|
if (!production) {
|
|
26564
|
-
console.debug(`[RxStateComputed] ${target.constructor?.name}.${key} ->
|
|
26507
|
+
console.debug(`[RxStateComputed] ${target.constructor?.name}.${key} -> state.select([${dependencies.map((d) => `'${d}'`).join(', ')}])`);
|
|
26565
26508
|
}
|
|
26566
26509
|
};
|
|
26567
26510
|
}
|
|
@@ -33709,10 +33652,17 @@ class FeedsComponent {
|
|
|
33709
33652
|
platform = inject(PlatformService);
|
|
33710
33653
|
router = inject(Router);
|
|
33711
33654
|
version;
|
|
33712
|
-
feeds
|
|
33713
|
-
hasFeeds
|
|
33714
|
-
feeds
|
|
33715
|
-
|
|
33655
|
+
feeds$ = this._state.select('feeds');
|
|
33656
|
+
hasFeeds$ = this._state.select('hasFeeds');
|
|
33657
|
+
set feeds(value) {
|
|
33658
|
+
this._state.set('feeds', () => value);
|
|
33659
|
+
}
|
|
33660
|
+
get feeds() {
|
|
33661
|
+
return this._state.get('feeds');
|
|
33662
|
+
}
|
|
33663
|
+
get hasFeeds() {
|
|
33664
|
+
return this._state.get('hasFeeds');
|
|
33665
|
+
}
|
|
33716
33666
|
showHeader = true;
|
|
33717
33667
|
headerTextColor = 'light';
|
|
33718
33668
|
constructor(environment, feedService) {
|
|
@@ -33768,18 +33718,6 @@ class FeedsComponent {
|
|
|
33768
33718
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedsComponent, deps: [{ token: ENVIRONMENT }, { token: APP_FEED_SERVICE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
33769
33719
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: FeedsComponent, selector: "app-feeds", inputs: { feeds: "feeds", showHeader: "showHeader", headerTextColor: "headerTextColor" }, providers: [RxState], ngImport: i0, template: "@if (feeds | isNotEmptyArray) {\n <div class=\"feed ion-padding-horizontal ion-no-padding ion-padding-top\">\n\n <!-- feeds -->\n @for (feed of feeds$ | push; track feed.feed_url) {\n\n <!-- top header -->\n @if (showHeader) {\n <ion-item lines=\"none\" color=\"secondary\">\n <ion-icon slot=\"start\" name=\"megaphone\"></ion-icon>\n <ion-label>\n <b>{{ feed.title || ('SOCIAL.FEED.NEWS'|translate) }}</b>\n </ion-label>\n <ion-button slot=\"end\" fill=\"clear\" (click)=\"openFeedHome()\">\n <ion-label translate>SOCIAL.FEED.SHOW_ALL_FEED</ion-label>\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\n </ion-button>\n </ion-item>\n }\n\n\n <!-- items -->\n @for (item of feed.items; track item.id) {\n <ion-card>\n <ion-card-header>\n <ion-card-subtitle style=\"vertical-align: middle\">\n\n <!-- Authors -->\n @for (author of (item.authors || feed.authors); track author) {\n @if (author.name || author.avatar) {\n <ion-chip (click)=\"openUrl(author.url)\" tappable>\n @if (author.avatar) {\n <ion-avatar>\n <ion-img [src]=\"author.avatar\" [alt]=\"author.name\"></ion-img>\n </ion-avatar>\n }\n @if (author.name) {\n <ion-label color=\"medium\">{{ author.name }}</ion-label>\n }\n </ion-chip>\n }\n }\n <ion-note class=\"ion-float-end\">\n <small>{{ item.date_published | dateFromNow }}</small>\n </ion-note>\n </ion-card-subtitle>\n\n <!-- title -->\n <ion-card-title (click)=\"openUrl(item.url || feed.feed_url)\" tappable>{{ item?.title }}</ion-card-title>\n\n <!-- tags -->\n @let tags = item | map: getTags;\n @if (tags | isNotEmptyArray) {\n <div class=\"tags\">\n @for (tag of tags; track tag; let last = $last) {\n <a (click)=\"openTag(feed, tag)\" tappable>\n <ion-text>#{{ tag }}</ion-text>\n </a>@if (!last) {\n \n }\n }\n </div>\n }\n </ion-card-header>\n\n <!-- Feed content -->\n <ion-card-content>\n <ion-text [feed]=\"item.url || feed.feed_url\">\n @if (item.content_html) {\n <p [innerHTML]=\"item.content_html\"></p>\n } @else if (item.content_text) {\n <p [innerText]=\"item.content_text\"></p>\n }\n </ion-text>\n </ion-card-content>\n\n <ion-button (click)=\"openUrl(item.url)\" class=\"ion-float-end\" fill=\"clear\">\n <ion-label>{{ (item.truncated ? 'SOCIAL.FEED.READ_MORE' : 'COMMON.BTN_SHOW') | translate }}</ion-label>\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\n </ion-button>\n </ion-card>\n }\n }\n </div>\n}\n", styles: [".feed ion-item{border-radius:12px 12px 0 0;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}.feed ion-item ion-icon[slot=start]{-webkit-margin-end:8px;margin-inline-end:8px}.feed .tags{display:inline}.feed .tags a{color:var(--ion-color-step-600, #666666)!important}.feed ion-card{--ion-card-background: rgba(var(--ion-background-color-rgb), .6);--ion-card-color: var(--ion-text-color);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);margin:0 0 16px}.feed ion-card ion-card-header ion-card-title{--color: var(--ion-text-color)}.feed ion-card ion-card-header ion-card-subtitle{--color: var(--ion-color-step-50)}.feed ion-card ion-card-header ion-chip{--background: transparent;--border-color: transparent;--border-width: 0}.feed ion-card ion-card-header ion-chip ion-avatar{border:1px solid var(--ion-color-primary)}.feed ion-card ion-card-header ion-chip ion-label{color:var(--color)}.feed ion-button{text-transform:unset;color:var(--ion-color-step-400)}.feed a:hover{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "component", type: i2$1.IonAvatar, selector: "ion-avatar" }, { kind: "component", type: i2$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2$1.IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: i2$1.IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: i2$1.IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: i2$1.IonCardSubtitle, selector: "ion-card-subtitle", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonChip, selector: "ion-chip", inputs: ["color", "disabled", "mode", "outline"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonImg, selector: "ion-img", inputs: ["alt", "src"] }, { kind: "component", type: i2$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2$1.IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: FeedDirective, selector: "feed,[feed]", inputs: ["feed"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: i19.RxPush, name: "push" }, { kind: "pipe", type: DateFromNowPipe, name: "dateFromNow" }, { kind: "pipe", type: NotEmptyArrayPipe, name: "isNotEmptyArray" }, { kind: "pipe", type: MapPipe, name: "map" }] });
|
|
33770
33720
|
}
|
|
33771
|
-
__decorate([
|
|
33772
|
-
RxStateSelect()
|
|
33773
|
-
], FeedsComponent.prototype, "feeds$", void 0);
|
|
33774
|
-
__decorate([
|
|
33775
|
-
RxStateSelect()
|
|
33776
|
-
], FeedsComponent.prototype, "hasFeeds$", void 0);
|
|
33777
|
-
__decorate([
|
|
33778
|
-
RxStateProperty()
|
|
33779
|
-
], FeedsComponent.prototype, "feeds", void 0);
|
|
33780
|
-
__decorate([
|
|
33781
|
-
RxStateProperty()
|
|
33782
|
-
], FeedsComponent.prototype, "hasFeeds", void 0);
|
|
33783
33721
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedsComponent, decorators: [{
|
|
33784
33722
|
type: Component,
|
|
33785
33723
|
args: [{ selector: 'app-feeds', providers: [RxState], template: "@if (feeds | isNotEmptyArray) {\n <div class=\"feed ion-padding-horizontal ion-no-padding ion-padding-top\">\n\n <!-- feeds -->\n @for (feed of feeds$ | push; track feed.feed_url) {\n\n <!-- top header -->\n @if (showHeader) {\n <ion-item lines=\"none\" color=\"secondary\">\n <ion-icon slot=\"start\" name=\"megaphone\"></ion-icon>\n <ion-label>\n <b>{{ feed.title || ('SOCIAL.FEED.NEWS'|translate) }}</b>\n </ion-label>\n <ion-button slot=\"end\" fill=\"clear\" (click)=\"openFeedHome()\">\n <ion-label translate>SOCIAL.FEED.SHOW_ALL_FEED</ion-label>\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\n </ion-button>\n </ion-item>\n }\n\n\n <!-- items -->\n @for (item of feed.items; track item.id) {\n <ion-card>\n <ion-card-header>\n <ion-card-subtitle style=\"vertical-align: middle\">\n\n <!-- Authors -->\n @for (author of (item.authors || feed.authors); track author) {\n @if (author.name || author.avatar) {\n <ion-chip (click)=\"openUrl(author.url)\" tappable>\n @if (author.avatar) {\n <ion-avatar>\n <ion-img [src]=\"author.avatar\" [alt]=\"author.name\"></ion-img>\n </ion-avatar>\n }\n @if (author.name) {\n <ion-label color=\"medium\">{{ author.name }}</ion-label>\n }\n </ion-chip>\n }\n }\n <ion-note class=\"ion-float-end\">\n <small>{{ item.date_published | dateFromNow }}</small>\n </ion-note>\n </ion-card-subtitle>\n\n <!-- title -->\n <ion-card-title (click)=\"openUrl(item.url || feed.feed_url)\" tappable>{{ item?.title }}</ion-card-title>\n\n <!-- tags -->\n @let tags = item | map: getTags;\n @if (tags | isNotEmptyArray) {\n <div class=\"tags\">\n @for (tag of tags; track tag; let last = $last) {\n <a (click)=\"openTag(feed, tag)\" tappable>\n <ion-text>#{{ tag }}</ion-text>\n </a>@if (!last) {\n \n }\n }\n </div>\n }\n </ion-card-header>\n\n <!-- Feed content -->\n <ion-card-content>\n <ion-text [feed]=\"item.url || feed.feed_url\">\n @if (item.content_html) {\n <p [innerHTML]=\"item.content_html\"></p>\n } @else if (item.content_text) {\n <p [innerText]=\"item.content_text\"></p>\n }\n </ion-text>\n </ion-card-content>\n\n <ion-button (click)=\"openUrl(item.url)\" class=\"ion-float-end\" fill=\"clear\">\n <ion-label>{{ (item.truncated ? 'SOCIAL.FEED.READ_MORE' : 'COMMON.BTN_SHOW') | translate }}</ion-label>\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\n </ion-button>\n </ion-card>\n }\n }\n </div>\n}\n", styles: [".feed ion-item{border-radius:12px 12px 0 0;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}.feed ion-item ion-icon[slot=start]{-webkit-margin-end:8px;margin-inline-end:8px}.feed .tags{display:inline}.feed .tags a{color:var(--ion-color-step-600, #666666)!important}.feed ion-card{--ion-card-background: rgba(var(--ion-background-color-rgb), .6);--ion-card-color: var(--ion-text-color);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);margin:0 0 16px}.feed ion-card ion-card-header ion-card-title{--color: var(--ion-text-color)}.feed ion-card ion-card-header ion-card-subtitle{--color: var(--ion-color-step-50)}.feed ion-card ion-card-header ion-chip{--background: transparent;--border-color: transparent;--border-width: 0}.feed ion-card ion-card-header ion-chip ion-avatar{border:1px solid var(--ion-color-primary)}.feed ion-card ion-card-header ion-chip ion-label{color:var(--color)}.feed ion-button{text-transform:unset;color:var(--ion-color-step-400)}.feed a:hover{color:var(--ion-color-medium)}\n"] }]
|
|
@@ -33791,9 +33729,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
33791
33729
|
}, {
|
|
33792
33730
|
type: Inject,
|
|
33793
33731
|
args: [APP_FEED_SERVICE]
|
|
33794
|
-
}] }], propDecorators: { feeds
|
|
33732
|
+
}] }], propDecorators: { feeds: [{
|
|
33795
33733
|
type: Input
|
|
33796
|
-
}],
|
|
33734
|
+
}], showHeader: [{
|
|
33797
33735
|
type: Input
|
|
33798
33736
|
}], headerTextColor: [{
|
|
33799
33737
|
type: Input
|