401 lines
24 KiB
JavaScript
401 lines
24 KiB
JavaScript
import {
|
|
BottomNav
|
|
} from "./chunk-JDU3HACN.js";
|
|
import {
|
|
DefaultValueAccessor,
|
|
FormsModule,
|
|
NgControlStatus,
|
|
NgModel
|
|
} from "./chunk-VD6QIYHN.js";
|
|
import {
|
|
CourseService
|
|
} from "./chunk-6K3TDILH.js";
|
|
import {
|
|
NzMessageService
|
|
} from "./chunk-GJYGTZ7J.js";
|
|
import {
|
|
AuthService,
|
|
NzIconDirective,
|
|
NzIconModule,
|
|
Router
|
|
} from "./chunk-2TRRHRR7.js";
|
|
import "./chunk-EDRPZB37.js";
|
|
import {
|
|
Component,
|
|
Input,
|
|
Output,
|
|
Subject,
|
|
debounceTime,
|
|
distinctUntilChanged,
|
|
inject,
|
|
input,
|
|
output,
|
|
setClassMetadata,
|
|
signal,
|
|
takeUntil,
|
|
ɵsetClassDebugInfo,
|
|
ɵɵProvidersFeature,
|
|
ɵɵadvance,
|
|
ɵɵconditional,
|
|
ɵɵconditionalCreate,
|
|
ɵɵdefineComponent,
|
|
ɵɵelement,
|
|
ɵɵelementEnd,
|
|
ɵɵelementStart,
|
|
ɵɵgetCurrentView,
|
|
ɵɵlistener,
|
|
ɵɵnextContext,
|
|
ɵɵproperty,
|
|
ɵɵpureFunction0,
|
|
ɵɵrepeater,
|
|
ɵɵrepeaterCreate,
|
|
ɵɵrepeaterTrackByIndex,
|
|
ɵɵresetView,
|
|
ɵɵrestoreView,
|
|
ɵɵtext,
|
|
ɵɵtextInterpolate,
|
|
ɵɵtextInterpolate2
|
|
} from "./chunk-WI7WFVZR.js";
|
|
import "./chunk-WDMUDEB6.js";
|
|
|
|
// src/app/components/course-card/course-card.ts
|
|
function CourseCard_Conditional_13_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
\u0275\u0275elementStart(0, "span", 9);
|
|
\u0275\u0275text(1);
|
|
\u0275\u0275elementEnd();
|
|
}
|
|
if (rf & 2) {
|
|
const ctx_r0 = \u0275\u0275nextContext();
|
|
\u0275\u0275advance();
|
|
\u0275\u0275textInterpolate2("\xB7 ", ctx_r0.course().topicCount, " sujet", ctx_r0.course().topicCount > 1 ? "s" : "");
|
|
}
|
|
}
|
|
var CourseCard = class _CourseCard {
|
|
course = input.required(...ngDevMode ? [{ debugName: "course" }] : []);
|
|
clicked = output();
|
|
onClick() {
|
|
this.clicked.emit(this.course());
|
|
}
|
|
static \u0275fac = function CourseCard_Factory(__ngFactoryType__) {
|
|
return new (__ngFactoryType__ || _CourseCard)();
|
|
};
|
|
static \u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _CourseCard, selectors: [["app-course-card"]], inputs: { course: [1, "course"] }, outputs: { clicked: "clicked" }, decls: 14, vars: 4, consts: [[1, "course-card", 3, "click"], [1, "card-header"], [1, "community-badge"], [1, "card-body"], [1, "course-title"], [1, "course-description"], [1, "card-footer"], ["nz-icon", "", "nzType", "user", "nzTheme", "outline", 1, "author-icon"], [1, "author-name"], [1, "topic-count"]], template: function CourseCard_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
\u0275\u0275elementStart(0, "div", 0);
|
|
\u0275\u0275listener("click", function CourseCard_Template_div_click_0_listener() {
|
|
return ctx.onClick();
|
|
});
|
|
\u0275\u0275elementStart(1, "div", 1)(2, "span", 2);
|
|
\u0275\u0275text(3, "COMMUNAUT\xC9");
|
|
\u0275\u0275elementEnd()();
|
|
\u0275\u0275elementStart(4, "div", 3)(5, "h3", 4);
|
|
\u0275\u0275text(6);
|
|
\u0275\u0275elementEnd();
|
|
\u0275\u0275elementStart(7, "p", 5);
|
|
\u0275\u0275text(8);
|
|
\u0275\u0275elementEnd()();
|
|
\u0275\u0275elementStart(9, "div", 6);
|
|
\u0275\u0275element(10, "span", 7);
|
|
\u0275\u0275elementStart(11, "span", 8);
|
|
\u0275\u0275text(12);
|
|
\u0275\u0275elementEnd();
|
|
\u0275\u0275conditionalCreate(13, CourseCard_Conditional_13_Template, 2, 2, "span", 9);
|
|
\u0275\u0275elementEnd()();
|
|
}
|
|
if (rf & 2) {
|
|
\u0275\u0275advance(6);
|
|
\u0275\u0275textInterpolate(ctx.course().title);
|
|
\u0275\u0275advance(2);
|
|
\u0275\u0275textInterpolate(ctx.course().description);
|
|
\u0275\u0275advance(4);
|
|
\u0275\u0275textInterpolate(ctx.course().creatorName);
|
|
\u0275\u0275advance();
|
|
\u0275\u0275conditional(ctx.course().topicCount > 0 ? 13 : -1);
|
|
}
|
|
}, dependencies: [NzIconModule, NzIconDirective], styles: ["\n\n.course-card[_ngcontent-%COMP%] {\n background-color: var(--card);\n border: 1px solid var(--border);\n border-radius: 16px;\n padding: 16px;\n cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n margin-bottom: 12px;\n}\n.course-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);\n}\n.card-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: 12px;\n}\n.book-icon-wrapper[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n background-color: var(--bg);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--border);\n}\n.book-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--text);\n}\n.community-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.08em;\n color: var(--text-muted);\n background-color: var(--bg);\n border: 1px solid var(--border);\n border-radius: 6px;\n padding: 3px 8px;\n}\n.card-body[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n}\n.course-title[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 700;\n color: var(--text);\n margin: 0 0 6px 0;\n line-height: 1.3;\n}\n.course-description[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--text-muted);\n margin: 0;\n line-height: 1.5;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.card-footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.author-icon[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--text-muted);\n}\n.author-name[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--text-muted);\n font-weight: 500;\n}\n.topic-count[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--text-muted);\n}\n/*# sourceMappingURL=course-card.css.map */"] });
|
|
};
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CourseCard, [{
|
|
type: Component,
|
|
args: [{ selector: "app-course-card", imports: [NzIconModule], template: `<div class="course-card" (click)="onClick()">
|
|
<div class="card-header">
|
|
<span class="community-badge">COMMUNAUT\xC9</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<h3 class="course-title">{{ course().title }}</h3>
|
|
<p class="course-description">{{ course().description }}</p>
|
|
</div>
|
|
<div class="card-footer">
|
|
<span nz-icon nzType="user" nzTheme="outline" class="author-icon"></span>
|
|
<span class="author-name">{{ course().creatorName }}</span>
|
|
@if (course().topicCount > 0) {
|
|
<span class="topic-count">\xB7 {{ course().topicCount }} sujet{{ course().topicCount > 1 ? 's' : '' }}</span>
|
|
}
|
|
</div>
|
|
</div>
|
|
`, styles: ["/* src/app/components/course-card/course-card.css */\n.course-card {\n background-color: var(--card);\n border: 1px solid var(--border);\n border-radius: 16px;\n padding: 16px;\n cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n margin-bottom: 12px;\n}\n.course-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);\n}\n.card-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: 12px;\n}\n.book-icon-wrapper {\n width: 44px;\n height: 44px;\n background-color: var(--bg);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--border);\n}\n.book-icon {\n font-size: 20px;\n color: var(--text);\n}\n.community-badge {\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.08em;\n color: var(--text-muted);\n background-color: var(--bg);\n border: 1px solid var(--border);\n border-radius: 6px;\n padding: 3px 8px;\n}\n.card-body {\n margin-bottom: 12px;\n}\n.course-title {\n font-size: 15px;\n font-weight: 700;\n color: var(--text);\n margin: 0 0 6px 0;\n line-height: 1.3;\n}\n.course-description {\n font-size: 13px;\n color: var(--text-muted);\n margin: 0;\n line-height: 1.5;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.card-footer {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.author-icon {\n font-size: 13px;\n color: var(--text-muted);\n}\n.author-name {\n font-size: 12px;\n color: var(--text-muted);\n font-weight: 500;\n}\n.topic-count {\n font-size: 12px;\n color: var(--text-muted);\n}\n/*# sourceMappingURL=course-card.css.map */\n"] }]
|
|
}], null, { course: [{ type: Input, args: [{ isSignal: true, alias: "course", required: true }] }], clicked: [{ type: Output, args: ["clicked"] }] });
|
|
})();
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(CourseCard, { className: "CourseCard", filePath: "src/app/components/course-card/course-card.ts", lineNumber: 11 });
|
|
})();
|
|
|
|
// src/app/pages/catalog/catalog.ts
|
|
var _c0 = () => [1, 2, 3];
|
|
var _forTrack0 = ($index, $item) => $item.id;
|
|
function CatalogPage_Conditional_20_For_2_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
\u0275\u0275element(0, "div", 20);
|
|
}
|
|
}
|
|
function CatalogPage_Conditional_20_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
\u0275\u0275elementStart(0, "div", 17);
|
|
\u0275\u0275repeaterCreate(1, CatalogPage_Conditional_20_For_2_Template, 1, 0, "div", 20, \u0275\u0275repeaterTrackByIndex);
|
|
\u0275\u0275elementEnd();
|
|
}
|
|
if (rf & 2) {
|
|
\u0275\u0275advance();
|
|
\u0275\u0275repeater(\u0275\u0275pureFunction0(0, _c0));
|
|
}
|
|
}
|
|
function CatalogPage_Conditional_21_Conditional_4_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
\u0275\u0275elementStart(0, "p", 23);
|
|
\u0275\u0275text(1, "Essayez un autre terme de recherche");
|
|
\u0275\u0275elementEnd();
|
|
}
|
|
}
|
|
function CatalogPage_Conditional_21_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
\u0275\u0275elementStart(0, "div", 18);
|
|
\u0275\u0275element(1, "span", 21);
|
|
\u0275\u0275elementStart(2, "p", 22);
|
|
\u0275\u0275text(3, "Aucun cours trouv\xE9");
|
|
\u0275\u0275elementEnd();
|
|
\u0275\u0275conditionalCreate(4, CatalogPage_Conditional_21_Conditional_4_Template, 2, 0, "p", 23);
|
|
\u0275\u0275elementEnd();
|
|
}
|
|
if (rf & 2) {
|
|
const ctx_r0 = \u0275\u0275nextContext();
|
|
\u0275\u0275advance(4);
|
|
\u0275\u0275conditional(ctx_r0.searchQuery() ? 4 : -1);
|
|
}
|
|
}
|
|
function CatalogPage_Conditional_22_For_2_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
const _r2 = \u0275\u0275getCurrentView();
|
|
\u0275\u0275elementStart(0, "app-course-card", 25);
|
|
\u0275\u0275listener("clicked", function CatalogPage_Conditional_22_For_2_Template_app_course_card_clicked_0_listener($event) {
|
|
\u0275\u0275restoreView(_r2);
|
|
const ctx_r0 = \u0275\u0275nextContext(2);
|
|
return \u0275\u0275resetView(ctx_r0.onCourseClicked($event));
|
|
});
|
|
\u0275\u0275elementEnd();
|
|
}
|
|
if (rf & 2) {
|
|
const course_r3 = ctx.$implicit;
|
|
\u0275\u0275property("course", course_r3);
|
|
}
|
|
}
|
|
function CatalogPage_Conditional_22_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
\u0275\u0275elementStart(0, "div", 19);
|
|
\u0275\u0275repeaterCreate(1, CatalogPage_Conditional_22_For_2_Template, 1, 1, "app-course-card", 24, _forTrack0);
|
|
\u0275\u0275elementEnd();
|
|
}
|
|
if (rf & 2) {
|
|
const ctx_r0 = \u0275\u0275nextContext();
|
|
\u0275\u0275advance();
|
|
\u0275\u0275repeater(ctx_r0.courses());
|
|
}
|
|
}
|
|
var CatalogPage = class _CatalogPage {
|
|
courseService = inject(CourseService);
|
|
authService = inject(AuthService);
|
|
router = inject(Router);
|
|
message = inject(NzMessageService);
|
|
destroy$ = new Subject();
|
|
search$ = new Subject();
|
|
courses = signal([], ...ngDevMode ? [{ debugName: "courses" }] : []);
|
|
loading = signal(false, ...ngDevMode ? [{ debugName: "loading" }] : []);
|
|
searchQuery = signal("", ...ngDevMode ? [{ debugName: "searchQuery" }] : []);
|
|
isDark = signal(true, ...ngDevMode ? [{ debugName: "isDark" }] : []);
|
|
get currentUser() {
|
|
return this.authService.currentUser();
|
|
}
|
|
ngOnInit() {
|
|
this.search$.pipe(debounceTime(400), distinctUntilChanged(), takeUntil(this.destroy$)).subscribe((query) => {
|
|
this.loadCourses(query);
|
|
});
|
|
this.loadCourses("");
|
|
}
|
|
ngOnDestroy() {
|
|
this.destroy$.next();
|
|
this.destroy$.complete();
|
|
}
|
|
onSearchChange(value) {
|
|
this.searchQuery.set(value);
|
|
this.search$.next(value);
|
|
}
|
|
loadCourses(search) {
|
|
this.loading.set(true);
|
|
this.courseService.getCourses(search).subscribe({
|
|
next: (courses) => {
|
|
this.courses.set(courses);
|
|
this.loading.set(false);
|
|
},
|
|
error: () => {
|
|
this.loading.set(false);
|
|
this.message.error("Impossible de charger les cours");
|
|
}
|
|
});
|
|
}
|
|
onCourseClicked(course) {
|
|
this.router.navigate(["/courses", course.id]);
|
|
}
|
|
toggleTheme() {
|
|
const html = document.documentElement;
|
|
if (html.classList.contains("dark")) {
|
|
html.classList.remove("dark");
|
|
this.isDark.set(false);
|
|
} else {
|
|
html.classList.add("dark");
|
|
this.isDark.set(true);
|
|
}
|
|
}
|
|
logout() {
|
|
this.authService.logout();
|
|
this.router.navigate(["/auth"]);
|
|
}
|
|
static \u0275fac = function CatalogPage_Factory(__ngFactoryType__) {
|
|
return new (__ngFactoryType__ || _CatalogPage)();
|
|
};
|
|
static \u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _CatalogPage, selectors: [["app-catalog"]], features: [\u0275\u0275ProvidersFeature([NzMessageService])], decls: 24, vars: 4, consts: [[1, "page-container", "catalog-page"], [1, "catalog-header"], [1, "header-top"], [1, "header-logo"], [1, "logo-text"], [1, "header-actions"], ["aria-label", "Toggle theme", 1, "icon-btn", 3, "click"], ["nz-icon", "", 3, "nzType", "nzTheme"], ["aria-label", "D\xE9connexion", 1, "icon-btn", 3, "click"], ["nz-icon", "", "nzType", "logout", "nzTheme", "outline"], [1, "catalog-title-section"], [1, "catalog-title"], [1, "catalog-subtitle"], [1, "search-wrapper"], ["nz-icon", "", "nzType", "search", "nzTheme", "outline", 1, "search-icon"], ["type", "search", "placeholder", "Rechercher des sujets, auteurs...", 1, "search-input", 3, "ngModelChange", "ngModel"], [1, "catalog-content"], [1, "loading-list"], [1, "empty-state"], [1, "courses-list"], [1, "skeleton-card"], ["nz-icon", "", "nzType", "read", "nzTheme", "outline", 1, "empty-icon"], [1, "empty-text"], [1, "empty-hint"], [3, "course"], [3, "clicked", "course"]], template: function CatalogPage_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
\u0275\u0275elementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "div", 3)(4, "span", 4);
|
|
\u0275\u0275text(5, "MetaCourse");
|
|
\u0275\u0275elementEnd()();
|
|
\u0275\u0275elementStart(6, "div", 5)(7, "button", 6);
|
|
\u0275\u0275listener("click", function CatalogPage_Template_button_click_7_listener() {
|
|
return ctx.toggleTheme();
|
|
});
|
|
\u0275\u0275element(8, "span", 7);
|
|
\u0275\u0275elementEnd();
|
|
\u0275\u0275elementStart(9, "button", 8);
|
|
\u0275\u0275listener("click", function CatalogPage_Template_button_click_9_listener() {
|
|
return ctx.logout();
|
|
});
|
|
\u0275\u0275element(10, "span", 9);
|
|
\u0275\u0275elementEnd()()();
|
|
\u0275\u0275elementStart(11, "div", 10)(12, "h1", 11);
|
|
\u0275\u0275text(13, "Explorer les Cours");
|
|
\u0275\u0275elementEnd();
|
|
\u0275\u0275elementStart(14, "p", 12);
|
|
\u0275\u0275text(15, "D\xE9couvrez de nouvelles comp\xE9tences.");
|
|
\u0275\u0275elementEnd()();
|
|
\u0275\u0275elementStart(16, "div", 13);
|
|
\u0275\u0275element(17, "span", 14);
|
|
\u0275\u0275elementStart(18, "input", 15);
|
|
\u0275\u0275listener("ngModelChange", function CatalogPage_Template_input_ngModelChange_18_listener($event) {
|
|
return ctx.onSearchChange($event);
|
|
});
|
|
\u0275\u0275elementEnd()()();
|
|
\u0275\u0275elementStart(19, "div", 16);
|
|
\u0275\u0275conditionalCreate(20, CatalogPage_Conditional_20_Template, 3, 1, "div", 17)(21, CatalogPage_Conditional_21_Template, 5, 1, "div", 18)(22, CatalogPage_Conditional_22_Template, 3, 0, "div", 19);
|
|
\u0275\u0275elementEnd();
|
|
\u0275\u0275element(23, "app-bottom-nav");
|
|
\u0275\u0275elementEnd();
|
|
}
|
|
if (rf & 2) {
|
|
\u0275\u0275advance(8);
|
|
\u0275\u0275property("nzType", ctx.isDark() ? "bulb" : "bulb")("nzTheme", ctx.isDark() ? "fill" : "outline");
|
|
\u0275\u0275advance(10);
|
|
\u0275\u0275property("ngModel", ctx.searchQuery());
|
|
\u0275\u0275advance(2);
|
|
\u0275\u0275conditional(ctx.loading() ? 20 : ctx.courses().length === 0 ? 21 : 22);
|
|
}
|
|
}, dependencies: [FormsModule, DefaultValueAccessor, NgControlStatus, NgModel, NzIconModule, NzIconDirective, CourseCard, BottomNav], styles: ["\n\n.catalog-page[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n padding-bottom: 80px;\n}\n.catalog-header[_ngcontent-%COMP%] {\n padding: 16px 20px 0;\n background-color: var(--bg);\n position: sticky;\n top: 0;\n z-index: 10;\n}\n.header-top[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 20px;\n}\n.header-logo[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.logo-icon[_ngcontent-%COMP%] {\n font-size: 22px;\n color: var(--text);\n}\n.logo-text[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 800;\n color: var(--text);\n letter-spacing: -0.3px;\n}\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n.icon-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n background: var(--card);\n border: 1px solid var(--border);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n font-size: 16px;\n color: var(--text);\n}\n.catalog-title-section[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n}\n.catalog-title[_ngcontent-%COMP%] {\n font-size: 28px;\n font-weight: 800;\n color: var(--text);\n margin: 0 0 4px;\n letter-spacing: -0.5px;\n}\n.catalog-subtitle[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--text-muted);\n margin: 0 0 16px;\n}\n.search-wrapper[_ngcontent-%COMP%] {\n position: relative;\n margin-bottom: 16px;\n}\n.search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--text-muted);\n font-size: 16px;\n z-index: 1;\n}\n.search-input[_ngcontent-%COMP%] {\n width: 100%;\n background-color: var(--card);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 12px 16px 12px 42px;\n color: var(--text);\n font-size: 14px;\n outline: none;\n transition: border-color 0.2s;\n}\n.search-input[_ngcontent-%COMP%]:focus {\n border-color: #1abc9c;\n}\n.search-input[_ngcontent-%COMP%]::placeholder {\n color: var(--text-muted);\n}\n.catalog-content[_ngcontent-%COMP%] {\n padding: 4px 20px 0;\n}\n.courses-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.loading-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.skeleton-card[_ngcontent-%COMP%] {\n height: 160px;\n background: var(--card);\n border: 1px solid var(--border);\n border-radius: 16px;\n animation: _ngcontent-%COMP%_skeleton-pulse 1.5s ease-in-out infinite;\n}\n@keyframes _ngcontent-%COMP%_skeleton-pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.4;\n }\n}\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n text-align: center;\n}\n.empty-icon[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--text-muted);\n margin-bottom: 16px;\n}\n.empty-text[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 600;\n color: var(--text);\n margin: 0 0 8px;\n}\n.empty-hint[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--text-muted);\n margin: 0;\n}\n/*# sourceMappingURL=catalog.css.map */"] });
|
|
};
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CatalogPage, [{
|
|
type: Component,
|
|
args: [{ selector: "app-catalog", imports: [FormsModule, NzIconModule, CourseCard, BottomNav], providers: [NzMessageService], template: `<div class="page-container catalog-page">
|
|
<!-- Header -->
|
|
<div class="catalog-header">
|
|
<div class="header-top">
|
|
<div class="header-logo">
|
|
<span class="logo-text">MetaCourse</span>
|
|
</div>
|
|
<div class="header-actions">
|
|
<button class="icon-btn" (click)="toggleTheme()" aria-label="Toggle theme">
|
|
<span nz-icon [nzType]="isDark() ? 'bulb' : 'bulb'" [nzTheme]="isDark() ? 'fill' : 'outline'"></span>
|
|
</button>
|
|
<button class="icon-btn" (click)="logout()" aria-label="D\xE9connexion">
|
|
<span nz-icon nzType="logout" nzTheme="outline"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="catalog-title-section">
|
|
<h1 class="catalog-title">Explorer les Cours</h1>
|
|
<p class="catalog-subtitle">D\xE9couvrez de nouvelles comp\xE9tences.</p>
|
|
</div>
|
|
|
|
<!-- Search -->
|
|
<div class="search-wrapper">
|
|
<span nz-icon nzType="search" nzTheme="outline" class="search-icon"></span>
|
|
<input
|
|
type="search"
|
|
class="search-input"
|
|
placeholder="Rechercher des sujets, auteurs..."
|
|
[ngModel]="searchQuery()"
|
|
(ngModelChange)="onSearchChange($event)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Course list -->
|
|
<div class="catalog-content">
|
|
@if (loading()) {
|
|
<div class="loading-list">
|
|
@for (_ of [1, 2, 3]; track $index) {
|
|
<div class="skeleton-card"></div>
|
|
}
|
|
</div>
|
|
} @else if (courses().length === 0) {
|
|
<div class="empty-state">
|
|
<span nz-icon nzType="read" nzTheme="outline" class="empty-icon"></span>
|
|
<p class="empty-text">Aucun cours trouv\xE9</p>
|
|
@if (searchQuery()) {
|
|
<p class="empty-hint">Essayez un autre terme de recherche</p>
|
|
}
|
|
</div>
|
|
} @else {
|
|
<div class="courses-list">
|
|
@for (course of courses(); track course.id) {
|
|
<app-course-card [course]="course" (clicked)="onCourseClicked($event)" />
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<app-bottom-nav />
|
|
</div>
|
|
`, styles: ["/* src/app/pages/catalog/catalog.css */\n.catalog-page {\n display: flex;\n flex-direction: column;\n padding-bottom: 80px;\n}\n.catalog-header {\n padding: 16px 20px 0;\n background-color: var(--bg);\n position: sticky;\n top: 0;\n z-index: 10;\n}\n.header-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 20px;\n}\n.header-logo {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.logo-icon {\n font-size: 22px;\n color: var(--text);\n}\n.logo-text {\n font-size: 18px;\n font-weight: 800;\n color: var(--text);\n letter-spacing: -0.3px;\n}\n.header-actions {\n display: flex;\n gap: 8px;\n}\n.icon-btn {\n width: 36px;\n height: 36px;\n background: var(--card);\n border: 1px solid var(--border);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n font-size: 16px;\n color: var(--text);\n}\n.catalog-title-section {\n margin-bottom: 16px;\n}\n.catalog-title {\n font-size: 28px;\n font-weight: 800;\n color: var(--text);\n margin: 0 0 4px;\n letter-spacing: -0.5px;\n}\n.catalog-subtitle {\n font-size: 14px;\n color: var(--text-muted);\n margin: 0 0 16px;\n}\n.search-wrapper {\n position: relative;\n margin-bottom: 16px;\n}\n.search-icon {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--text-muted);\n font-size: 16px;\n z-index: 1;\n}\n.search-input {\n width: 100%;\n background-color: var(--card);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 12px 16px 12px 42px;\n color: var(--text);\n font-size: 14px;\n outline: none;\n transition: border-color 0.2s;\n}\n.search-input:focus {\n border-color: #1abc9c;\n}\n.search-input::placeholder {\n color: var(--text-muted);\n}\n.catalog-content {\n padding: 4px 20px 0;\n}\n.courses-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.loading-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.skeleton-card {\n height: 160px;\n background: var(--card);\n border: 1px solid var(--border);\n border-radius: 16px;\n animation: skeleton-pulse 1.5s ease-in-out infinite;\n}\n@keyframes skeleton-pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.4;\n }\n}\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n text-align: center;\n}\n.empty-icon {\n font-size: 48px;\n color: var(--text-muted);\n margin-bottom: 16px;\n}\n.empty-text {\n font-size: 18px;\n font-weight: 600;\n color: var(--text);\n margin: 0 0 8px;\n}\n.empty-hint {\n font-size: 14px;\n color: var(--text-muted);\n margin: 0;\n}\n/*# sourceMappingURL=catalog.css.map */\n"] }]
|
|
}], null, null);
|
|
})();
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(CatalogPage, { className: "CatalogPage", filePath: "src/app/pages/catalog/catalog.ts", lineNumber: 20 });
|
|
})();
|
|
|
|
// src/app/pages/catalog/catalog.routes.ts
|
|
var CATALOG_ROUTES = [
|
|
{ path: "", component: CatalogPage }
|
|
];
|
|
export {
|
|
CATALOG_ROUTES
|
|
};
|
|
//# sourceMappingURL=chunk-IM6TR7DF.js.map
|