1import { 2 SyncService 3} from "./chunk-FX3P6WNJ.js"; 4import "./chunk-OTQ6GTAJ.js"; 5import { 6 IonBadge, 7 IonButtons, 8 IonCard, 9 IonCardContent, 10 IonCardHeader, 11 IonContent, 12 IonFab, 13 IonFabButton, 14 IonHeader, 15 IonMenuButton, 16 IonRefresher, 17 IonRefresherContent, 18 IonSpinner, 19 IonTitle, 20 IonToolbar 21} from "./chunk-RLZ522BW.js"; 22import { 23 DatabaseService, 24 EntityType 25} from "./chunk-RLJCY5HS.js"; 26import "./chunk-GR5DEE5Y.js"; 27import { 28 TranslateModule, 29 TranslatePipe 30} from "./chunk-O5XYYQCR.js"; 31import { 32 AuthService, 33 UserRole 34} from "./chunk-QGEJYSW7.js"; 35import { 36 ApiUrlService 37} from "./chunk-MAIAEXGG.js"; 38import "./chunk-L4O6SE3A.js"; 39import "./chunk-INK5THDW.js"; 40import { 41 NgIcon, 42 lucideCalendar, 43 lucideChevronRight, 44 lucideNewspaper, 45 lucidePlus, 46 lucideSearchX, 47 lucideStar, 48 lucideUser, 49 provideIcons 50} from "./chunk-GMPIA5L4.js"; 51import { 52 CommonModule, 53 Component, 54 DatePipe, 55 EventEmitter, 56 Input, 57 Output, 58 Router, 59 setClassMetadata, 60 ɵsetClassDebugInfo, 61 ɵɵProvidersFeature, 62 ɵɵadvance, 63 ɵɵconditional, 64 ɵɵdefineComponent, 65 ɵɵdirectiveInject, 66 ɵɵelement, 67 ɵɵelementEnd, 68 ɵɵelementStart, 69 ɵɵgetCurrentView, 70 ɵɵlistener, 71 ɵɵnextContext, 72 ɵɵpipe, 73 ɵɵpipeBind1, 74 ɵɵpipeBind2, 75 ɵɵproperty, 76 ɵɵrepeater, 77 ɵɵrepeaterCreate, 78 ɵɵresetView, 79 ɵɵrestoreView, 80 ɵɵsanitizeUrl, 81 ɵɵtemplate, 82 ɵɵtext, 83 ɵɵtextInterpolate, 84 ɵɵtextInterpolate1 85} from "./chunk-UQ6LLOJ6.js"; 86import "./chunk-BD3NMR2S.js"; 87import "./chunk-6HPUB4U6.js"; 88import "./chunk-WGFJL45C.js"; 89import "./chunk-7WVISTDL.js"; 90import "./chunk-2S57T3GS.js"; 91import "./chunk-R4QHACMO.js"; 92import "./chunk-4MEJEBWM.js"; 93import "./chunk-RIBVNXHQ.js"; 94import "./chunk-Z42OVMMO.js"; 95import "./chunk-O5S42IXR.js"; 96import "./chunk-QBR2RTFG.js"; 97import "./chunk-MIOLVGSM.js"; 98import "./chunk-V3YFOG6Q.js"; 99import "./chunk-LPMBLWVS.js"; 100import "./chunk-ITE2OHLM.js"; 101import "./chunk-C46CB72A.js"; 102import "./chunk-SRPSML5O.js"; 103import "./chunk-NRSVX4KN.js"; 104import "./chunk-T4GYAOTA.js"; 105import "./chunk-2VHYZHLL.js"; 106import "./chunk-S6LHOZ5A.js"; 107import "./chunk-Y6HZOH3Q.js"; 108import "./chunk-TWQHADEW.js"; 109import "./chunk-3J4L7S6G.js"; 110import "./chunk-IL42VKT6.js"; 111import "./chunk-LONO5O5R.js"; 112import "./chunk-KFBF5L4X.js"; 113import "./chunk-PWC4K6CW.js"; 114import "./chunk-R6JLIESI.js"; 115import "./chunk-UG6K57PI.js"; 116import "./chunk-UR6VIRNL.js"; 117import "./chunk-OJO5RD3M.js"; 118import { 119 __async 120} from "./chunk-CO64IJQE.js"; 121
122// src/app/components/news-card/news-card.component.ts 123function NewsCardComponent_Conditional_0_Conditional_1_Template(rf, ctx) { 124 if (rf & 1) { 125 \u0275\u0275elementStart(0, "div", 3); 126 \u0275\u0275element(1, "img", 10); 127 \u0275\u0275elementEnd(); 128 } 129 if (rf & 2) { 130 const ctx_r1 = \u0275\u0275nextContext(2); 131 \u0275\u0275advance(); 132 \u0275\u0275property("src", ctx_r1.imageUrl, \u0275\u0275sanitizeUrl)("alt", ctx_r1.news.entity.title); 133 } 134} 135function NewsCardComponent_Conditional_0_Conditional_3_Template(rf, ctx) { 136 if (rf & 1) { 137 \u0275\u0275elementStart(0, "ion-badge", 4); 138 \u0275\u0275element(1, "ng-icon", 11); 139 \u0275\u0275text(2); 140 \u0275\u0275pipe(3, "translate"); 141 \u0275\u0275elementEnd(); 142 } 143 if (rf & 2) { 144 \u0275\u0275advance(2); 145 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(3, 1, "news.featured"), " "); 146 } 147} 148function NewsCardComponent_Conditional_0_Conditional_14_Template(rf, ctx) { 149 if (rf & 1) { 150 \u0275\u0275elementStart(0, "span", 8); 151 \u0275\u0275element(1, "ng-icon", 12); 152 \u0275\u0275text(2); 153 \u0275\u0275elementEnd(); 154 } 155 if (rf & 2) { 156 const ctx_r1 = \u0275\u0275nextContext(2); 157 \u0275\u0275advance(2); 158 \u0275\u0275textInterpolate1(" ", ctx_r1.authorName, " "); 159 } 160} 161function NewsCardComponent_Conditional_0_Template(rf, ctx) { 162 if (rf & 1) { 163 const _r1 = \u0275\u0275getCurrentView(); 164 \u0275\u0275elementStart(0, "ion-card", 2); 165 \u0275\u0275listener("click", function NewsCardComponent_Conditional_0_Template_ion_card_click_0_listener() { 166 \u0275\u0275restoreView(_r1); 167 const ctx_r1 = \u0275\u0275nextContext(); 168 return \u0275\u0275resetView(ctx_r1.onClick()); 169 }); 170 \u0275\u0275template(1, NewsCardComponent_Conditional_0_Conditional_1_Template, 2, 2, "div", 3); 171 \u0275\u0275elementStart(2, "ion-card-header"); 172 \u0275\u0275template(3, NewsCardComponent_Conditional_0_Conditional_3_Template, 4, 3, "ion-badge", 4); 173 \u0275\u0275elementStart(4, "h2", 5); 174 \u0275\u0275text(5); 175 \u0275\u0275elementEnd()(); 176 \u0275\u0275elementStart(6, "ion-card-content")(7, "p", 6); 177 \u0275\u0275text(8); 178 \u0275\u0275elementEnd(); 179 \u0275\u0275elementStart(9, "div", 7)(10, "span", 8); 180 \u0275\u0275element(11, "ng-icon", 9); 181 \u0275\u0275text(12); 182 \u0275\u0275pipe(13, "date"); 183 \u0275\u0275elementEnd(); 184 \u0275\u0275template(14, NewsCardComponent_Conditional_0_Conditional_14_Template, 3, 1, "span", 8); 185 \u0275\u0275elementEnd()()(); 186 } 187 if (rf & 2) { 188 const ctx_r1 = \u0275\u0275nextContext(); 189 \u0275\u0275advance(); 190 \u0275\u0275conditional(ctx_r1.imageUrl ? 1 : -1); 191 \u0275\u0275advance(2); 192 \u0275\u0275conditional(ctx_r1.news.entity.isFeatured ? 3 : -1); 193 \u0275\u0275advance(2); 194 \u0275\u0275textInterpolate(ctx_r1.news.entity.title); 195 \u0275\u0275advance(3); 196 \u0275\u0275textInterpolate(ctx_r1.excerpt); 197 \u0275\u0275advance(4); 198 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind2(13, 6, ctx_r1.publishedDate, "mediumDate"), " "); 199 \u0275\u0275advance(2); 200 \u0275\u0275conditional(ctx_r1.authorName ? 14 : -1); 201 } 202} 203function NewsCardComponent_Conditional_1_Conditional_2_Template(rf, ctx) { 204 if (rf & 1) { 205 \u0275\u0275elementStart(0, "div", 15); 206 \u0275\u0275element(1, "img", 10); 207 \u0275\u0275elementEnd(); 208 } 209 if (rf & 2) { 210 const ctx_r1 = \u0275\u0275nextContext(2); 211 \u0275\u0275advance(); 212 \u0275\u0275property("src", ctx_r1.imageUrl, \u0275\u0275sanitizeUrl)("alt", ctx_r1.news.entity.title); 213 } 214} 215function NewsCardComponent_Conditional_1_Conditional_3_Template(rf, ctx) { 216 if (rf & 1) { 217 \u0275\u0275elementStart(0, "div", 16); 218 \u0275\u0275element(1, "ng-icon", 22); 219 \u0275\u0275elementEnd(); 220 } 221} 222function NewsCardComponent_Conditional_1_Conditional_5_Template(rf, ctx) { 223 if (rf & 1) { 224 \u0275\u0275elementStart(0, "ion-badge", 18); 225 \u0275\u0275text(1); 226 \u0275\u0275pipe(2, "translate"); 227 \u0275\u0275elementEnd(); 228 } 229 if (rf & 2) { 230 \u0275\u0275advance(); 231 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind1(2, 1, "news.featured"), " "); 232 } 233} 234function NewsCardComponent_Conditional_1_Template(rf, ctx) { 235 if (rf & 1) { 236 const _r3 = \u0275\u0275getCurrentView(); 237 \u0275\u0275elementStart(0, "ion-card", 13); 238 \u0275\u0275listener("click", function NewsCardComponent_Conditional_1_Template_ion_card_click_0_listener() { 239 \u0275\u0275restoreView(_r3); 240 const ctx_r1 = \u0275\u0275nextContext();
241 return \u0275\u0275resetView(ctx_r1.onClick()); 242 }); 243 \u0275\u0275elementStart(1, "div", 14); 244 \u0275\u0275template(2, NewsCardComponent_Conditional_1_Conditional_2_Template, 2, 2, "div", 15)(3, NewsCardComponent_Conditional_1_Conditional_3_Template, 2, 0, "div", 16); 245 \u0275\u0275elementStart(4, "div", 17); 246 \u0275\u0275template(5, NewsCardComponent_Conditional_1_Conditional_5_Template, 3, 3, "ion-badge", 18); 247 \u0275\u0275elementStart(6, "h3", 5); 248 \u0275\u0275text(7); 249 \u0275\u0275elementEnd(); 250 \u0275\u0275elementStart(8, "p", 6); 251 \u0275\u0275text(9); 252 \u0275\u0275elementEnd(); 253 \u0275\u0275elementStart(10, "div", 7)(11, "span", 8); 254 \u0275\u0275element(12, "ng-icon", 19); 255 \u0275\u0275text(13); 256 \u0275\u0275pipe(14, "date"); 257 \u0275\u0275elementEnd()()(); 258 \u0275\u0275elementStart(15, "div", 20); 259 \u0275\u0275element(16, "ng-icon", 21); 260 \u0275\u0275elementEnd()()(); 261 } 262 if (rf & 2) { 263 const ctx_r1 = \u0275\u0275nextContext(); 264 \u0275\u0275advance(2); 265 \u0275\u0275conditional(ctx_r1.imageUrl ? 2 : 3); 266 \u0275\u0275advance(3); 267 \u0275\u0275conditional(ctx_r1.news.entity.isFeatured ? 5 : -1); 268 \u0275\u0275advance(2); 269 \u0275\u0275textInterpolate(ctx_r1.news.entity.title); 270 \u0275\u0275advance(2); 271 \u0275\u0275textInterpolate(ctx_r1.excerpt); 272 \u0275\u0275advance(4); 273 \u0275\u0275textInterpolate1(" ", \u0275\u0275pipeBind2(14, 5, ctx_r1.publishedDate, "mediumDate"), " "); 274 } 275} 276var _NewsCardComponent = class _NewsCardComponent { 277 constructor(apiUrlService) { 278 this.apiUrlService = apiUrlService; 279 this.variant = "compact"; 280 this.cardClick = new EventEmitter(); 281 } 282 get imageUrl() { 283 if (!this.news.entity.imageUploadId) 284 return null; 285 return `${this.apiUrlService.getSelectedUrl()}/api/v1/media/${this.news.entity.imageUploadId}`; 286 } 287 get authorName() { 288 var _a; 289 return ((_a = this.news.author) == null ? void 0 : _a.entity.name) || null; 290 } 291 get publishedDate() { 292 if (!this.news.entity.publishedAt) 293 return null; 294 return new Date(this.news.entity.publishedAt); 295 } 296 get excerpt() { 297 const content = this.news.entity.content || ""; 298 const maxLength = this.variant === "featured" ? 150 : 80; 299 if (content.length <= maxLength) 300 return content; 301 return content.substring(0, maxLength).trim() + "..."; 302 } 303 onClick() { 304 this.cardClick.emit(this.news); 305 } 306}; 307_NewsCardComponent.\u0275fac = function NewsCardComponent_Factory(__ngFactoryType__) { 308 return new (__ngFactoryType__ || _NewsCardComponent)(\u0275\u0275directiveInject(ApiUrlService)); 309}; 310_NewsCardComponent.\u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _NewsCardComponent, selectors: [["app-news-card"]], inputs: { news: "news", variant: "variant" }, outputs: { cardClick: "cardClick" }, features: [\u0275\u0275ProvidersFeature([], [provideIcons({ lucideCalendar, lucideUser, lucideChevronRight, lucideStar })])], decls: 2, vars: 1, consts: [[1, "news-card", "featured"], [1, "news-card", "compact"], [1, "news-card", "featured", 3, "click"], [1, "card-image", "featured-image"], ["color", "warning", 1, "featured-badge"], [1, "card-title"], [1, "card-excerpt"], [1, "card-meta"], [1, "meta-item"], ["name", "lucideCalendar", "size", "1em"], [3, "src", "alt"], ["name", "lucideStar", "size", "0.9em"], ["name", "lucideUser", "size", "1em"], [1, "news-card", "compact", 3, "click"], [1, "compact-layout"], [1, "card-image", "compact-image"], [1, "card-image", "compact-image", "placeholder"], [1, "card-content"], ["color", "warning", 1, "featured-badge", "small"], ["name", "lucideCalendar", "size", "0.9em"], [1, "card-arrow"], ["name", "lucideChevronRight", "size", "1.2em"], ["name", "lucideStar", "size", "1.5em"]], template: function NewsCardComponent_Template(rf, ctx) { 311 if (rf & 1) { 312 \u0275\u0275template(0, NewsCardComponent_Conditional_0_Template, 15, 9, "ion-card", 0)(1, NewsCardComponent_Conditional_1_Template, 17, 8, "ion-card", 1); 313 } 314 if (rf & 2) { 315 \u0275\u0275conditional(ctx.variant === "featured" ? 0 : 1); 316 } 317}, dependencies: [ 318 CommonModule, 319 DatePipe, 320 TranslateModule, 321 TranslatePipe, 322 NgIcon, 323 IonCard,
324 IonCardHeader, 325 IonCardContent, 326 IonBadge 327], styles: ["\n\n.news-card[_ngcontent-%COMP%] {\n cursor: pointer;\n margin: 0 0 12px 0;\n border-radius: 12px;\n overflow: hidden;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n}\n.news-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n.news-card[_ngcontent-%COMP%]:active {\n transform: translateY(0);\n}\n.news-card.featured[_ngcontent-%COMP%] .featured-image[_ngcontent-%COMP%] {\n width: 100%;\n height: 180px;\n overflow: hidden;\n}\n.news-card.featured[_ngcontent-%COMP%] .featured-image[_ngcontent-%COMP%] img[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.news-card.featured[_ngcontent-%COMP%] ion-card-header[_ngcontent-%COMP%] {\n padding: 12px 16px 8px;\n}\n.news-card.featured[_ngcontent-%COMP%] ion-card-content[_ngcontent-%COMP%] {\n padding: 0 16px 16px;\n}\n.news-card.featured[_ngcontent-%COMP%] .card-title[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n font-weight: 600;\n margin: 8px 0;\n line-height: 1.3;\n color: var(--ion-text-color);\n}\n.news-card.featured[_ngcontent-%COMP%] .card-excerpt[_ngcontent-%COMP%] {\n font-size: 0.95rem;\n color: var(--ion-color-medium);\n margin: 0 0 12px;\n line-height: 1.5;\n}\n.news-card.compact[_ngcontent-%COMP%] .compact-layout[_ngcontent-%COMP%] {\n display: flex;\n align-items: stretch;\n padding: 12px;\n gap: 12px;\n}\n.news-card.compact[_ngcontent-%COMP%] .compact-image[_ngcontent-%COMP%] {\n flex-shrink: 0;\n width: 70px;\n height: 70px;\n border-radius: 8px;\n overflow: hidden;\n background: var(--ion-color-light);\n}\n.news-card.compact[_ngcontent-%COMP%] .compact-image[_ngcontent-%COMP%] img[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.news-card.compact[_ngcontent-%COMP%] .compact-image.placeholder[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--ion-color-medium);\n}\n.news-card.compact[_ngcontent-%COMP%] .card-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n.news-card.compact[_ngcontent-%COMP%] .card-title[_ngcontent-%COMP%] {\n font-size: 1rem;\n font-weight: 600;\n margin: 0 0 4px;\n line-height: 1.3;\n color: var(--ion-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.news-card.compact[_ngcontent-%COMP%] .card-excerpt[_ngcontent-%COMP%] {\n font-size: 0.85rem;\n color: var(--ion-color-medium);\n margin: 0 0 6px;\n line-height: 1.4;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.news-card.compact[_ngcontent-%COMP%] .card-arrow[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n color: var(--ion-color-medium);\n}\n.featured-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n.featured-badge.small[_ngcontent-%COMP%] {\n font-size: 0.65rem;\n padding: 2px 6px;\n margin-bottom: 4px;\n}\n.card-meta[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n font-size: 0.8rem;\n color: var(--ion-color-medium);\n}\n.card-meta[_ngcontent-%COMP%] .meta-item[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}"] }); 328var NewsCardComponent = _NewsCardComponent; 329(() => { 330 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(NewsCardComponent, [{ 331 type: Component, 332 args: [{ selector: "app-news-card", standalone: true, imports: [ 333 CommonModule, 334 TranslateModule, 335 NgIcon, 336 IonCard, 337 IonCardHeader, 338 IonCardContent, 339 IonBadge 340 ], viewProviders: [provideIcons({ lucideCalendar, lucideUser, lucideChevronRight, lucideStar })], template: `@if (variant === 'featured') { 341 <ion-card class="news-card featured" (click)="onClick()"> 342 @if (imageUrl) { 343 <div class="card-image featured-image"> 344 <img [src]="imageUrl" [alt]="news.entity.title" /> 345 </div> 346 } 347 <ion-card-header> 348 @if (news.entity.isFeatured) { 349 <ion-badge color="warning" class="featured-badge"> 350 <ng-icon name="lucideStar" size="0.9em"></ng-icon> 351 {{ 'news.featured' | translate }} 352 </ion-badge> 353 } 354 <h2 class="card-title">{{ news.entity.title }}</h2> 355 </ion-card-header> 356 <ion-card-content> 357 <p class="card-excerpt">{{ excerpt }}</p> 358 <div class="card-meta">
359 <span class="meta-item"> 360 <ng-icon name="lucideCalendar" size="1em"></ng-icon> 361 {{ publishedDate | date:'mediumDate' }} 362 </span> 363 @if (authorName) { 364 <span class="meta-item"> 365 <ng-icon name="lucideUser" size="1em"></ng-icon> 366 {{ authorName }} 367 </span> 368 } 369 </div> 370 </ion-card-content> 371 </ion-card> 372} @else { 373 <ion-card class="news-card compact" (click)="onClick()"> 374 <div class="compact-layout"> 375 @if (imageUrl) { 376 <div class="card-image compact-image"> 377 <img [src]="imageUrl" [alt]="news.entity.title" /> 378 </div> 379 } @else { 380 <div class="card-image compact-image placeholder"> 381 <ng-icon name="lucideStar" size="1.5em"></ng-icon> 382 </div> 383 } 384 <div class="card-content"> 385 @if (news.entity.isFeatured) { 386 <ion-badge color="warning" class="featured-badge small"> 387 {{ 'news.featured' | translate }} 388 </ion-badge> 389 } 390 <h3 class="card-title">{{ news.entity.title }}</h3> 391 <p class="card-excerpt">{{ excerpt }}</p> 392 <div class="card-meta"> 393 <span class="meta-item"> 394 <ng-icon name="lucideCalendar" size="0.9em"></ng-icon> 395 {{ publishedDate | date:'mediumDate' }} 396 </span> 397 </div> 398 </div> 399 <div class="card-arrow"> 400 <ng-icon name="lucideChevronRight" size="1.2em"></ng-icon> 401 </div> 402 </div> 403 </ion-card> 404} 405`, styles: ["/* src/app/components/news-card/news-card.component.scss */\n.news-card {\n cursor: pointer;\n margin: 0 0 12px 0;\n border-radius: 12px;\n overflow: hidden;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n}\n.news-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n.news-card:active {\n transform: translateY(0);\n}\n.news-card.featured .featured-image {\n width: 100%;\n height: 180px;\n overflow: hidden;\n}\n.news-card.featured .featured-image img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.news-card.featured ion-card-header {\n padding: 12px 16px 8px;\n}\n.news-card.featured ion-card-content {\n padding: 0 16px 16px;\n}\n.news-card.featured .card-title {\n font-size: 1.25rem;\n font-weight: 600;\n margin: 8px 0;\n line-height: 1.3;\n color: var(--ion-text-color);\n}\n.news-card.featured .card-excerpt {\n font-size: 0.95rem;\n color: var(--ion-color-medium);\n margin: 0 0 12px;\n line-height: 1.5;\n}\n.news-card.compact .compact-layout {\n display: flex;\n align-items: stretch;\n padding: 12px;\n gap: 12px;\n}\n.news-card.compact .compact-image {\n flex-shrink: 0;\n width: 70px;\n height: 70px;\n border-radius: 8px;\n overflow: hidden;\n background: var(--ion-color-light);\n}\n.news-card.compact .compact-image img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.news-card.compact .compact-image.placeholder {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--ion-color-medium);\n}\n.news-card.compact .card-content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n.news-card.compact .card-title {\n font-size: 1rem;\n font-weight: 600;\n margin: 0 0 4px;\n line-height: 1.3;\n color: var(--ion-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.news-card.compact .card-excerpt {\n font-size: 0.85rem;\n color: var(--ion-color-medium);\n margin: 0 0 6px;\n line-height: 1.4;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.news-card.compact .card-arrow {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n color: var(--ion-color-medium);\n}\n.featured-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 0.75rem;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n.featured-badge.small {\n font-size: 0.65rem;\n padding: 2px 6px;\n margin-bottom: 4px;\n}\n.card-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n font-size: 0.8rem;\n color: var(--ion-color-medium);\n}\n.card-meta .meta-item {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n"] }] 406 }], () => [{ type: ApiUrlService }], { news: [{ 407 type: Input 408 }], variant: [{ 409 type: Input 410 }], cardClick: [{ 411 type: Output 412 }] }); 413})(); 414(() => { 415 (typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(NewsCardComponent, { className: "NewsCardComponent", filePath: "src/app/components/news-card/news-card.component.ts", lineNumber: 27 }); 416})(); 417
418// src/app/pages/news/news.page.ts 419var _forTrack0 = ($index, $item) => $item.entity.id; 420function NewsPage_Conditional_10_Template(rf, ctx) { 421 if (rf & 1) { 422 \u0275\u0275elementStart(0, "div", 2); 423 \u0275\u0275element(1, "ion-spinner", 6); 424 \u0275\u0275elementStart(2, "p"); 425 \u0275\u0275text(3); 426 \u0275\u0275pipe(4, "translate"); 427 \u0275\u0275elementEnd()(); 428 } 429 if (rf & 2) { 430 \u0275\u0275advance(3); 431 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(4, 1, "news.loading")); 432 } 433} 434function NewsPage_Conditional_11_Template(rf, ctx) { 435 if (rf & 1) { 436 \u0275\u0275elementStart(0, "div", 3); 437 \u0275\u0275element(1, "ng-icon", 7); 438 \u0275\u0275elementStart(2, "h3"); 439 \u0275\u0275text(3); 440 \u0275\u0275pipe(4, "translate"); 441 \u0275\u0275elementEnd(); 442 \u0275\u0275elementStart(5, "p"); 443 \u0275\u0275text(6); 444 \u0275\u0275pipe(7, "translate"); 445 \u0275\u0275elementEnd()(); 446 } 447 if (rf & 2) { 448 \u0275\u0275advance(3); 449 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(4, 2, "news.empty")); 450 \u0275\u0275advance(3); 451 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(7, 4, "news.emptyDescription")); 452 } 453} 454function NewsPage_Conditional_12_For_2_Template(rf, ctx) { 455 if (rf & 1) { 456 const _r1 = \u0275\u0275getCurrentView(); 457 \u0275\u0275elementStart(0, "app-news-card", 10); 458 \u0275\u0275listener("cardClick", function NewsPage_Conditional_12_For_2_Template_app_news_card_cardClick_0_listener($event) { 459 \u0275\u0275restoreView(_r1); 460 const ctx_r1 = \u0275\u0275nextContext(2); 461 return \u0275\u0275resetView(ctx_r1.onNewsClick($event)); 462 }); 463 \u0275\u0275elementEnd(); 464 } 465 if (rf & 2) { 466 const news_r3 = ctx.$implicit; 467 \u0275\u0275property("news", news_r3); 468 } 469} 470function NewsPage_Conditional_12_For_4_Template(rf, ctx) { 471 if (rf & 1) { 472 const _r4 = \u0275\u0275getCurrentView(); 473 \u0275\u0275elementStart(0, "app-news-card", 11); 474 \u0275\u0275listener("cardClick", function NewsPage_Conditional_12_For_4_Template_app_news_card_cardClick_0_listener($event) { 475 \u0275\u0275restoreView(_r4); 476 const ctx_r1 = \u0275\u0275nextContext(2); 477 return \u0275\u0275resetView(ctx_r1.onNewsClick($event)); 478 }); 479 \u0275\u0275elementEnd(); 480 } 481 if (rf & 2) { 482 const news_r5 = ctx.$implicit; 483 \u0275\u0275property("news", news_r5); 484 } 485} 486function NewsPage_Conditional_12_Template(rf, ctx) { 487 if (rf & 1) { 488 \u0275\u0275elementStart(0, "div", 4); 489 \u0275\u0275repeaterCreate(1, NewsPage_Conditional_12_For_2_Template, 1, 1, "app-news-card", 8, _forTrack0); 490 \u0275\u0275repeaterCreate(3, NewsPage_Conditional_12_For_4_Template, 1, 1, "app-news-card", 9, _forTrack0); 491 \u0275\u0275elementEnd(); 492 } 493 if (rf & 2) { 494 const ctx_r1 = \u0275\u0275nextContext(); 495 \u0275\u0275advance(); 496 \u0275\u0275repeater(ctx_r1.featuredNews); 497 \u0275\u0275advance(2); 498 \u0275\u0275repeater(ctx_r1.regularNews); 499 } 500} 501function NewsPage_Conditional_13_Template(rf, ctx) { 502 if (rf & 1) { 503 const _r6 = \u0275\u0275getCurrentView(); 504 \u0275\u0275elementStart(0, "ion-fab", 5)(1, "ion-fab-button", 12); 505 \u0275\u0275listener("click", function NewsPage_Conditional_13_Template_ion_fab_button_click_1_listener() { 506 \u0275\u0275restoreView(_r6); 507 const ctx_r1 = \u0275\u0275nextContext(); 508 return \u0275\u0275resetView(ctx_r1.onCreateNews()); 509 }); 510 \u0275\u0275element(2, "ng-icon", 13); 511 \u0275\u0275elementEnd()(); 512 } 513} 514var _NewsPage = class _NewsPage { 515 constructor(databaseService, authService, syncService, router) { 516 this.databaseService = databaseService; 517 this.authService = authService; 518 this.syncService = syncService; 519 this.router = router; 520 this.loading = true; 521 this.allNews = []; 522 } 523 ngOnInit() { 524 this.loadNews(); 525 } 526 get canCreateNews() { 527 return this.authService.hasRole(UserRole.Moderator); 528 } 529 get userCampusIds() { 530 var _a; 531 const campusIds = []; 532 for (const [, model] of this.databaseService.Models) { 533 if (model.type === EntityType.PERSON_CAMPUS) { 534 const pc = model.entity; 535 if (pc.personId === ((_a = this.authService.currentUserValue) == null ? void 0 : _a.id) && pc.campusId) { 536 campusIds.push(pc.campusId); 537 } 538 } 539 } 540 if (this.authService.hasRole(UserRole.Admin)) { 541 for (const [, model] of this.databaseService.Models) { 542 if (model.type === EntityType.CAMPUS && !model.entity.isDeleted) { 543 if (!campusIds.includes(model.entity.id)) { 544 campusIds.push(model.entity.id); 545 } 546 } 547 } 548 } 549 return campusIds; 550 } 551 get sortedNews() { 552 return this.allNews.filter((n) => !n.entity.isDeleted).filter((n) => this.userCampusIds.includes(n.entity.campusId)).sort((a, b) => { 553 if (a.entity.isFeatured && !b.entity.isFeatured) 554 return -1; 555 if (!a.entity.isFeatured && b.entity.isFeatured) 556 return 1; 557 const dateA = new Date(a.entity.publishedAt || 0).getTime(); 558 const dateB = new Date(b.entity.publishedAt || 0).getTime(); 559 return dateB - dateA; 560 }); 561 } 562 get featuredNews() { 563 return this.sortedNews.filter((n) => n.entity.isFeatured); 564 } 565 get regularNews() { 566 return this.sortedNews.filter((n) => !n.entity.isFeatured); 567 } 568 loadNews() { 569 this.allNews = []; 570 for (const [, model] of this.databaseService.Models) { 571 if (model.type === EntityType.NEWS) { 572 this.allNews.push(model); 573 } 574 } 575 this.loading = false;
576 } 577 doRefresh(event) { 578 return __async(this, null, function* () { 579 try { 580 yield this.syncService.pullData(); 581 this.loadNews(); 582 } finally { 583 event.target.complete(); 584 } 585 }); 586 } 587 onNewsClick(news) { 588 this.router.navigate(["/news", news.entity.id]); 589 } 590 onCreateNews() { 591 this.router.navigate(["/news/new"]); 592 } 593}; 594_NewsPage.\u0275fac = function NewsPage_Factory(__ngFactoryType__) { 595 return new (__ngFactoryType__ || _NewsPage)(\u0275\u0275directiveInject(DatabaseService), \u0275\u0275directiveInject(AuthService), \u0275\u0275directiveInject(SyncService), \u0275\u0275directiveInject(Router)); 596}; 597_NewsPage.\u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _NewsPage, selectors: [["app-news"]], features: [\u0275\u0275ProvidersFeature([], [provideIcons({ lucideNewspaper, lucidePlus, lucideSearchX })])], decls: 14, vars: 5, consts: [["slot", "start"], ["slot", "fixed", 3, "ionRefresh"], [1, "loading-container"], [1, "empty-state"], [1, "news-list"], ["vertical", "bottom", "horizontal", "end", "slot", "fixed"], ["name", "crescent"], ["name", "lucideNewspaper", "size", "3em"], ["variant", "featured", 3, "news"], ["variant", "compact", 3, "news"], ["variant", "featured", 3, "cardClick", "news"], ["variant", "compact", 3, "cardClick", "news"], [3, "click"], ["name", "lucidePlus", "size", "1.5em"]], template: function NewsPage_Template(rf, ctx) { 598 if (rf & 1) { 599 \u0275\u0275elementStart(0, "ion-header")(1, "ion-toolbar")(2, "ion-buttons", 0); 600 \u0275\u0275element(3, "ion-menu-button"); 601 \u0275\u0275elementEnd(); 602 \u0275\u0275elementStart(4, "ion-title"); 603 \u0275\u0275text(5); 604 \u0275\u0275pipe(6, "translate"); 605 \u0275\u0275elementEnd()()(); 606 \u0275\u0275elementStart(7, "ion-content")(8, "ion-refresher", 1); 607 \u0275\u0275listener("ionRefresh", function NewsPage_Template_ion_refresher_ionRefresh_8_listener($event) { 608 return ctx.doRefresh($event); 609 }); 610 \u0275\u0275element(9, "ion-refresher-content"); 611 \u0275\u0275elementEnd(); 612 \u0275\u0275template(10, NewsPage_Conditional_10_Template, 5, 3, "div", 2)(11, NewsPage_Conditional_11_Template, 8, 6, "div", 3)(12, NewsPage_Conditional_12_Template, 5, 0, "div", 4)(13, NewsPage_Conditional_13_Template, 3, 0, "ion-fab", 5); 613 \u0275\u0275elementEnd(); 614 } 615 if (rf & 2) { 616 \u0275\u0275advance(5); 617 \u0275\u0275textInterpolate(\u0275\u0275pipeBind1(6, 3, "news.title")); 618 \u0275\u0275advance(5); 619 \u0275\u0275conditional(ctx.loading ? 10 : ctx.sortedNews.length === 0 ? 11 : 12); 620 \u0275\u0275advance(3); 621 \u0275\u0275conditional(ctx.canCreateNews ? 13 : -1); 622 } 623}, dependencies: [ 624 CommonModule, 625 TranslateModule, 626 TranslatePipe, 627 NgIcon, 628 NewsCardComponent, 629 IonHeader, 630 IonToolbar, 631 IonButtons, 632 IonMenuButton, 633 IonTitle, 634 IonContent, 635 IonFab, 636 IonFabButton, 637 IonRefresher, 638 IonRefresherContent, 639 IonSpinner 640], styles: ["\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 50vh;\n gap: 16px;\n color: var(--ion-color-medium);\n}\n.loading-container[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 0.95rem;\n}\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 50vh;\n padding: 24px;\n text-align: center;\n color: var(--ion-color-medium);\n}\n.empty-state[_ngcontent-%COMP%] ng-icon[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n opacity: 0.6;\n}\n.empty-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--ion-text-color);\n}\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 0.95rem;\n}\n.news-list[_ngcontent-%COMP%] {\n padding: 16px;\n padding-bottom: 80px;\n}\n@media (min-width: 768px) {\n .news-list[_ngcontent-%COMP%] {\n max-width: 800px;\n margin: 0 auto;\n }\n}\nion-fab-button[_ngcontent-%COMP%] {\n --background: var(--ion-color-primary);\n --color: var(--ion-color-primary-contrast);\n}\nion-fab-button[_ngcontent-%COMP%] ng-icon[_ngcontent-%COMP%] {\n color: inherit;\n}"] }); 641var NewsPage = _NewsPage; 642(() => { 643 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(NewsPage, [{ 644 type: Component, 645 args: [{ selector: "app-news", standalone: true, imports: [ 646 CommonModule, 647 TranslateModule, 648 NgIcon, 649 NewsCardComponent, 650 IonHeader, 651 IonToolbar, 652 IonButtons, 653 IonMenuButton, 654 IonTitle, 655 IonContent, 656 IonFab, 657 IonFabButton, 658 IonRefresher, 659 IonRefresherContent, 660 IonSpinner 661 ], viewProviders: [provideIcons({ lucideNewspaper, lucidePlus, lucideSearchX })], template: `<ion-header> 662 <ion-toolbar> 663 <ion-buttons slot="start"> 664 <ion-menu-button></ion-menu-button> 665 </ion-buttons> 666 <ion-title>{{ 'news.title' | translate }}</ion-title> 667 </ion-toolbar> 668</ion-header> 669 670<ion-content> 671 <ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)"> 672 <ion-refresher-content></ion-refresher-content> 673 </ion-refresher> 674 675 @if (loading) { 676 <div class="loading-container"> 677 <ion-spinner name="crescent"></ion-spinner> 678 <p>{{ 'news.loading' | translate }}</p> 679 </div> 680 } @else if (sortedNews.length === 0) { 681 <div class="empty-state"> 682 <ng-icon name="lucideNewspaper" size="3em"></ng-icon> 683 <h3>{{ 'news.empty' | translate }}</h3> 684 <p>{{ 'news.emptyDescription' | translate }}</p> 685 </div> 686 } @else { 687 <div class="news-list"> 688 <!-- Featured news as hero cards --> 689 @for (news of featuredNews; track news.entity.id) { 690 <app-news-card 691 [news]="news" 692 variant="featured"
693 (cardClick)="onNewsClick($event)"> 694 </app-news-card> 695 } 696 697 <!-- Regular news as compact cards --> 698 @for (news of regularNews; track news.entity.id) { 699 <app-news-card 700 [news]="news" 701 variant="compact" 702 (cardClick)="onNewsClick($event)"> 703 </app-news-card> 704 } 705 </div> 706 } 707 708 @if (canCreateNews) { 709 <ion-fab vertical="bottom" horizontal="end" slot="fixed"> 710 <ion-fab-button (click)="onCreateNews()"> 711 <ng-icon name="lucidePlus" size="1.5em"></ng-icon> 712 </ion-fab-button> 713 </ion-fab> 714 } 715</ion-content> 716`, styles: ["/* src/app/pages/news/news.page.scss */\n.loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 50vh;\n gap: 16px;\n color: var(--ion-color-medium);\n}\n.loading-container p {\n margin: 0;\n font-size: 0.95rem;\n}\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 50vh;\n padding: 24px;\n text-align: center;\n color: var(--ion-color-medium);\n}\n.empty-state ng-icon {\n margin-bottom: 16px;\n opacity: 0.6;\n}\n.empty-state h3 {\n margin: 0 0 8px;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--ion-text-color);\n}\n.empty-state p {\n margin: 0;\n font-size: 0.95rem;\n}\n.news-list {\n padding: 16px;\n padding-bottom: 80px;\n}\n@media (min-width: 768px) {\n .news-list {\n max-width: 800px;\n margin: 0 auto;\n }\n}\nion-fab-button {\n --background: var(--ion-color-primary);\n --color: var(--ion-color-primary-contrast);\n}\nion-fab-button ng-icon {\n color: inherit;\n}\n"] }] 717 }], () => [{ type: DatabaseService }, { type: AuthService }, { type: SyncService }, { type: Router }], null); 718})(); 719(() => { 720 (typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(NewsPage, { className: "NewsPage", filePath: "src/app/pages/news/news.page.ts", lineNumber: 45 }); 721})(); 722export { 723 NewsPage 724};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.