diff --git a/demo/src/app/components/accordion/accordion.routes.ts b/demo/src/app/components/accordion/accordion.routes.ts index d06a590a8f..15aee9a53d 100644 --- a/demo/src/app/components/accordion/accordion.routes.ts +++ b/demo/src/app/components/accordion/accordion.routes.ts @@ -1,8 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdAccordionBasic } from './demos/basic/accordion-basic'; import { NgbdAccordionConfig } from './demos/config/accordion-config'; import { NgbdAccordionHeader } from './demos/header/accordion-header'; @@ -10,7 +9,6 @@ import { NgbdAccordionStatic } from './demos/static/accordion-static'; import { NgbdAccordionToggle } from './demos/toggle/accordion-toggle'; import { NgbdAccordionKeepContent } from './demos/keep-content/accordion-keep-content'; import { Routes } from '@angular/router'; -import { NgbdDemoListService } from '../../services/demo-list.service'; import { NgbdAccordionOverviewComponent } from './overview/accordion-overview.component'; import { NgbdAcccordionDeprecationComponent } from './accordion-deprecation.component'; @@ -20,44 +18,50 @@ const OVERVIEW = { customization: 'Customization', }; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Accordion', code: 'accordion/demos/basic/accordion-basic.ts', markup: 'accordion/demos/basic/accordion-basic.html', type: NgbdAccordionBasic, }, - static: { + { + fragment: 'static', title: 'One open panel at a time', code: 'accordion/demos/static/accordion-static.ts', markup: 'accordion/demos/static/accordion-static.html', type: NgbdAccordionStatic, }, - toggle: { + { + fragment: 'toggle', title: 'Toggle panels', code: 'accordion/demos/toggle/accordion-toggle.ts', markup: 'accordion/demos/toggle/accordion-toggle.html', type: NgbdAccordionToggle, }, - header: { + { + fragment: 'header', title: 'Custom header', code: 'accordion/demos/header/accordion-header.ts', markup: 'accordion/demos/header/accordion-header.html', type: NgbdAccordionHeader, }, - 'keep-content': { + { + fragment: 'keep-content', title: 'Keep content', code: 'accordion/demos/keep-content/accordion-keep-content.ts', markup: 'accordion/demos/keep-content/accordion-keep-content.html', type: NgbdAccordionKeepContent, }, - config: { + { + fragment: 'config', title: 'Global configuration of accordions', code: 'accordion/demos/config/accordion-config.ts', markup: 'accordion/demos/config/accordion-config.html', type: NgbdAccordionConfig, }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'overview' }, @@ -69,16 +73,17 @@ export const ROUTES: Routes = [ bootstrap: 'https://getbootstrap.com/docs/%version%/components/accordion/', header: NgbdAcccordionDeprecationComponent, }, - providers: [ + children: [ { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('accordion', DEMOS, OVERVIEW), + path: 'overview', + component: NgbdAccordionOverviewComponent, + data: { overview: OVERVIEW }, + }, + { + path: 'examples', + component: DemoListComponent, + data: { demos: DEMOS }, }, - ], - children: [ - { path: 'overview', component: NgbdAccordionOverviewComponent }, - { path: 'examples', component: NgbdExamplesPage }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/accordion/overview/accordion-overview.component.html b/demo/src/app/components/accordion/overview/accordion-overview.component.html index 128eb87623..2d3e997571 100644 --- a/demo/src/app/components/accordion/overview/accordion-overview.component.html +++ b/demo/src/app/components/accordion/overview/accordion-overview.component.html @@ -2,7 +2,7 @@

Since 14.1.0

- +

We're using a set of accordion directives and matching exactly the markup of the

For more details please refer to the complete API

-
+ - +

One panel at a time

@@ -61,9 +61,9 @@

Events

-
+ - +

You can provide a different template for accordion headers. In this case we would recommend changing the ngbAccordionHeader markup and using ngbAccordionToggle on the element that toggles a @@ -79,4 +79,4 @@

Events

Please see a working example for more details

-
+ diff --git a/demo/src/app/components/accordion/overview/accordion-overview.component.ts b/demo/src/app/components/accordion/overview/accordion-overview.component.ts index f22adf8cbb..37d53680cf 100644 --- a/demo/src/app/components/accordion/overview/accordion-overview.component.ts +++ b/demo/src/app/components/accordion/overview/accordion-overview.component.ts @@ -1,32 +1,33 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, Input } from '@angular/core'; import { Snippet } from '../../../services/snippet'; -import { NgbdDemoListService } from '../../../services/demo-list.service'; import { CodeComponent } from '../../../shared/code.component'; import { NgbAlertModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbdApiDocsBadge } from '../../../shared/api-docs'; import { RouterLink } from '@angular/router'; -import { NgbdOverviewSectionComponent } from '../../../shared/overview/overview-section.component'; -import { NgbdOverview } from '../../../shared/overview/overview'; import { NgbdAccordionDemoComponent } from './demo/accordion-overview-demo.component'; +import { PageHeaderComponent } from '../../../shared/page-header.component'; import { LIB_VERSIONS } from '../../../tokens'; @Component({ selector: 'ngbd-accordion-overview', standalone: true, imports: [ - NgbdOverviewSectionComponent, CodeComponent, NgbAlertModule, NgbdApiDocsBadge, RouterLink, NgbdAccordionDemoComponent, + PageHeaderComponent, ], templateUrl: './accordion-overview.component.html', changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class.overview]': 'true' }, }) export class NgbdAccordionOverviewComponent { + bootstrapVersion = inject(LIB_VERSIONS).bootstrap; + @Input() overview: { fragment: string; title: string }; + BASIC_ACCORDION = Snippet({ lang: 'html', code: ` @@ -108,11 +109,4 @@ export class NgbdAccordionOverviewComponent { `, }); - - bootstrapVersion = inject(LIB_VERSIONS).bootstrap; - sections: NgbdOverview = {}; - - constructor(demoList: NgbdDemoListService) { - this.sections = demoList.getOverviewSections('accordion'); - } } diff --git a/demo/src/app/components/alert/alert.routes.ts b/demo/src/app/components/alert/alert.routes.ts index bbc282eaaa..898264fa7b 100644 --- a/demo/src/app/components/alert/alert.routes.ts +++ b/demo/src/app/components/alert/alert.routes.ts @@ -2,48 +2,51 @@ import { Routes } from '@angular/router'; import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; import { NgbdAlertBasic } from './demos/basic/alert-basic'; import { NgbdAlertCloseable } from './demos/closeable/alert-closeable'; import { NgbdAlertSelfclosing } from './demos/selfclosing/alert-selfclosing'; import { NgbdAlertCustom } from './demos/custom/alert-custom'; import { NgbdAlertConfig } from './demos/config/alert-config'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Basic Alert', type: NgbdAlertBasic, code: 'alert/demos/basic/alert-basic.ts', markup: 'alert/demos/basic/alert-basic.html', }, - closeable: { + { + fragment: 'closeable', title: 'Closable Alert', type: NgbdAlertCloseable, code: 'alert/demos/closeable/alert-closeable.ts', markup: 'alert/demos/closeable/alert-closeable.html', }, - selfclosing: { + { + fragment: 'selfclosing', title: 'Self closing alert', type: NgbdAlertSelfclosing, code: 'alert/demos/selfclosing/alert-selfclosing.ts', markup: 'alert/demos/selfclosing/alert-selfclosing.html', }, - custom: { + { + fragment: 'custom', title: 'Custom alert', type: NgbdAlertCustom, code: 'alert/demos/custom/alert-custom.ts', markup: 'alert/demos/custom/alert-custom.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of alerts', type: NgbdAlertConfig, code: 'alert/demos/config/alert-config.ts', markup: 'alert/demos/config/alert-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -54,15 +57,8 @@ export const ROUTES: Routes = [ name: 'Alert', bootstrap: 'https://getbootstrap.com/docs/%version%/components/alerts/', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('alert', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/carousel/carousel.routes.ts b/demo/src/app/components/carousel/carousel.routes.ts index 3e58cc7489..d6911739ff 100644 --- a/demo/src/app/components/carousel/carousel.routes.ts +++ b/demo/src/app/components/carousel/carousel.routes.ts @@ -1,41 +1,43 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; -import { NgbdDemoListService } from '../../services/demo-list.service'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdCarouselBasic } from './demos/basic/carousel-basic'; import { NgbdCarouselConfig } from './demos/config/carousel-config'; import { NgbdCarouselNavigation } from './demos/navigation/carousel-navigation'; import { NgbdCarouselPause } from './demos/pause/carousel-pause'; import { Routes } from '@angular/router'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Carousel', type: NgbdCarouselBasic, code: 'carousel/demos/basic/carousel-basic.ts', markup: 'carousel/demos/basic/carousel-basic.html', }, - navigation: { + { + fragment: 'navigation', title: 'Navigation arrows and indicators', type: NgbdCarouselNavigation, code: 'carousel/demos/navigation/carousel-navigation.ts', markup: 'carousel/demos/navigation/carousel-navigation.html', }, - pause: { + { + fragment: 'pause', title: 'Pause/cycle', type: NgbdCarouselPause, code: 'carousel/demos/pause/carousel-pause.ts', markup: 'carousel/demos/pause/carousel-pause.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of carousels', type: NgbdCarouselConfig, code: 'carousel/demos/config/carousel-config.ts', markup: 'carousel/demos/config/carousel-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -46,15 +48,8 @@ export const ROUTES: Routes = [ name: 'Carousel', bootstrap: 'https://getbootstrap.com/docs/%version%/components/carousel/', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('carousel', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/collapse/collapse.routes.ts b/demo/src/app/components/collapse/collapse.routes.ts index 416d573841..9d9b83e0fb 100644 --- a/demo/src/app/components/collapse/collapse.routes.ts +++ b/demo/src/app/components/collapse/collapse.routes.ts @@ -1,34 +1,35 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; -import { NgbdDemoListService } from '../../services/demo-list.service'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdCollapseBasic } from './demos/basic/collapse-basic'; import { NgbdCollapseHorizontal } from './demos/horizontal/collapse-horizontal'; import { NgbdCollapseNavbar } from './demos/navbar/collapse-navbar'; import { Routes } from '@angular/router'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Collapse', type: NgbdCollapseBasic, code: 'collapse/demos/basic/collapse-basic.ts', markup: 'collapse/demos/basic/collapse-basic.html', }, - horizontal: { + { + fragment: 'horizontal', title: 'Horizontal collapse', type: NgbdCollapseHorizontal, code: 'collapse/demos/horizontal/collapse-horizontal.ts', markup: 'collapse/demos/horizontal/collapse-horizontal.html', }, - navbar: { + { + fragment: 'navbar', title: 'Responsive Navbar', type: NgbdCollapseNavbar, code: 'collapse/demos/navbar/collapse-navbar.ts', markup: 'collapse/demos/navbar/collapse-navbar.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -39,15 +40,8 @@ export const ROUTES: Routes = [ name: 'Collapse', bootstrap: 'https://getbootstrap.com/docs/%version%/components/collapse/', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('collapse', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/datepicker/calendars/datepicker-calendars.component.ts b/demo/src/app/components/datepicker/calendars/datepicker-calendars.component.ts index f89902b5b0..e7e926b59d 100644 --- a/demo/src/app/components/datepicker/calendars/datepicker-calendars.component.ts +++ b/demo/src/app/components/datepicker/calendars/datepicker-calendars.component.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { Snippet } from '../../../services/snippet'; -import { NgbdExamplesPage } from '../../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../../shared/examples-page/demo-list.component'; import { NgbdDatepickerHebrew } from '../demos/hebrew/datepicker-hebrew'; import { NgbdDatepickerIslamiccivil } from '../demos/islamiccivil/datepicker-islamiccivil'; import { NgbdDatepickerIslamicumalqura } from '../demos/islamicumalqura/datepicker-islamicumalqura'; @@ -13,37 +13,37 @@ import { CodeComponent } from '../../../shared/code.component'; import { NgbdWidgetDemoComponent } from '../../../shared/examples-page/demo.component'; import { NgComponentOutlet, NgFor } from '@angular/common'; -const DEMOS = [ +export const DEMOS = [ { - id: 'hebrew', + fragment: 'hebrew', title: 'Hebrew', type: NgbdDatepickerHebrew, code: 'datepicker/demos/hebrew/datepicker-hebrew.ts', markup: 'datepicker/demos/hebrew/datepicker-hebrew.html', }, { - id: 'jalali', + fragment: 'jalali', title: 'Jalali', type: NgbdDatepickerJalali, code: 'datepicker/demos/jalali/datepicker-jalali.ts', markup: 'datepicker/demos/jalali/datepicker-jalali.html', }, { - id: 'islamiccivil', + fragment: 'islamiccivil', title: 'Islamic Civil', type: NgbdDatepickerIslamiccivil, code: 'datepicker/demos/islamiccivil/datepicker-islamiccivil.ts', markup: 'datepicker/demos/islamiccivil/datepicker-islamiccivil.html', }, { - id: 'islamicumalqura', + fragment: 'islamicumalqura', title: 'Islamic Umm al-Qura', type: NgbdDatepickerIslamicumalqura, code: 'datepicker/demos/islamicumalqura/datepicker-islamicumalqura.ts', markup: 'datepicker/demos/islamicumalqura/datepicker-islamicumalqura.html', }, { - id: 'buddhist', + fragment: 'buddhist', title: 'Buddhist', type: NgbdDatepickerBuddhist, code: 'datepicker/demos/buddhist/datepicker-buddhist.ts', @@ -92,7 +92,7 @@ const DEMOS = [ `, }) -export class NgbdDatepickerCalendarsComponent extends NgbdExamplesPage { - demos = DEMOS; - +export class NgbdDatepickerCalendarsComponent extends DemoListComponent { snippets = { calendars: Snippet({ lang: 'typescript', diff --git a/demo/src/app/components/datepicker/datepicker.routes.ts b/demo/src/app/components/datepicker/datepicker.routes.ts index f7cb2a3eb7..c7de6eb2dd 100644 --- a/demo/src/app/components/datepicker/datepicker.routes.ts +++ b/demo/src/app/components/datepicker/datepicker.routes.ts @@ -1,9 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; -import { NgbdDemoListService } from '../../services/demo-list.service'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdDatepickerCalendarsComponent } from './calendars/datepicker-calendars.component'; import { NgbdDatepickerAdapter } from './demos/adapter/datepicker-adapter'; import { NgbdDatepickerBasic } from './demos/basic/datepicker-basic'; @@ -21,6 +19,7 @@ import { NgbdDatepickerOverviewComponent } from './overview/datepicker-overview. import { NgbdDatepickerPositiontarget } from './demos/positiontarget/datepicker-positiontarget'; import { NgbdDatepickerKeyboard } from './demos/keyboard/datepicker-keyboard'; import { Routes } from '@angular/router'; +import { DEMOS as CALENDAR_DEMOS } from './calendars/datepicker-calendars.component'; const OVERVIEW = { 'basic-usage': 'Basic Usage', @@ -37,92 +36,106 @@ const OVERVIEW = { 'keyboard-shortcuts': 'Keyboard shortcuts', }; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Basic datepicker', type: NgbdDatepickerBasic, code: 'datepicker/demos/basic/datepicker-basic.ts', markup: 'datepicker/demos/basic/datepicker-basic.html', }, - popup: { + { + fragment: 'popup', title: 'Datepicker in a popup', type: NgbdDatepickerPopup, code: 'datepicker/demos/popup/datepicker-popup.ts', markup: 'datepicker/demos/popup/datepicker-popup.html', }, - multiple: { + { + fragment: 'multiple', title: 'Multiple months', type: NgbdDatepickerMultiple, code: 'datepicker/demos/multiple/datepicker-multiple.ts', markup: 'datepicker/demos/multiple/datepicker-multiple.html', }, - range: { + { + fragment: 'range', title: 'Range selection', type: NgbdDatepickerRange, code: 'datepicker/demos/range/datepicker-range.ts', markup: 'datepicker/demos/range/datepicker-range.html', }, - 'range-popup': { + { + fragment: 'range-popup', title: 'Range selection in a popup', type: NgbdDatepickerRangePopup, code: 'datepicker/demos/range-popup/datepicker-range-popup.ts', markup: 'datepicker/demos/range-popup/datepicker-range-popup.html', }, - disabled: { + { + fragment: 'disabled', title: 'Disabled datepicker', type: NgbdDatepickerDisabled, code: 'datepicker/demos/disabled/datepicker-disabled.ts', markup: 'datepicker/demos/disabled/datepicker-disabled.html', }, - adapter: { + { + fragment: 'adapter', title: 'Custom date adapter and formatter', type: NgbdDatepickerAdapter, code: 'datepicker/demos/adapter/datepicker-adapter.ts', markup: 'datepicker/demos/adapter/datepicker-adapter.html', }, - i18n: { + { + fragment: 'i18n', title: 'Internationalization of datepickers', type: NgbdDatepickerI18n, code: 'datepicker/demos/i18n/datepicker-i18n.ts', markup: 'datepicker/demos/i18n/datepicker-i18n.html', }, - customday: { + { + fragment: 'customday', title: 'Custom day view', type: NgbdDatepickerCustomday, code: 'datepicker/demos/customday/datepicker-customday.ts', markup: 'datepicker/demos/customday/datepicker-customday.html', }, - custommonth: { + { + fragment: 'custommonth', title: 'Custom month layout', type: NgbdDatepickerCustommonth, code: 'datepicker/demos/custommonth/datepicker-custommonth.ts', markup: 'datepicker/demos/custommonth/datepicker-custommonth.html', }, - footertemplate: { + { + fragment: 'footertemplate', title: 'Footer template', type: NgbdDatepickerFootertemplate, code: 'datepicker/demos/footertemplate/datepicker-footertemplate.ts', markup: 'datepicker/demos/footertemplate/datepicker-footertemplate.html', }, - positiontarget: { + { + fragment: 'positiontarget', title: 'Position target', type: NgbdDatepickerPositiontarget, code: 'datepicker/demos/positiontarget/datepicker-positiontarget.ts', markup: 'datepicker/demos/positiontarget/datepicker-positiontarget.html', }, - keyboard: { + { + fragment: 'keyboard', title: 'Custom keyboard navigation', type: NgbdDatepickerKeyboard, code: 'datepicker/demos/keyboard/datepicker-keyboard.ts', markup: 'datepicker/demos/keyboard/datepicker-keyboard.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of datepickers', type: NgbdDatepickerConfig, code: 'datepicker/demos/config/datepicker-config.ts', markup: 'datepicker/demos/config/datepicker-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'overview' }, @@ -132,17 +145,22 @@ export const ROUTES: Routes = [ data: { name: 'Datepicker', }, - providers: [ + children: [ { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('datepicker', DEMOS, OVERVIEW), + path: 'overview', + component: NgbdDatepickerOverviewComponent, + data: { overview: OVERVIEW }, + }, + { + path: 'examples', + component: DemoListComponent, + data: { demos: DEMOS }, + }, + { + path: 'calendars', + component: NgbdDatepickerCalendarsComponent, + data: { demos: CALENDAR_DEMOS }, }, - ], - children: [ - { path: 'overview', component: NgbdDatepickerOverviewComponent }, - { path: 'examples', component: NgbdExamplesPage }, - { path: 'calendars', component: NgbdDatepickerCalendarsComponent }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/datepicker/overview/datepicker-overview.component.html b/demo/src/app/components/datepicker/overview/datepicker-overview.component.html index d430ba3668..dd72efb035 100644 --- a/demo/src/app/components/datepicker/overview/datepicker-overview.component.html +++ b/demo/src/app/components/datepicker/overview/datepicker-overview.component.html @@ -11,7 +11,7 @@ - +

Datepicker can be used either inline or inside of the popup.

@@ -66,14 +66,15 @@

Handling the popup

When using a button (or any other element) to open the popup, the styling and content of the button is left up to you. In the example above, the button is simply given the text "Toggle", but you could also use an icon, or even - group the input and button with an + group the + input and button with an input group.

-
+ - +

You have several ways of knowing when user selects a date. The date is selected either by clicking on it, pressing Space or Enter, typing text in the input or programmatically. @@ -87,7 +88,7 @@

Handling the popup

The model, however, is NOT a native javascript date, see the following - Date Model section for more info. + Date Model section for more info.

@@ -99,10 +100,10 @@

Handling the popup

-
+ - +

Datepicker uses NgbDateStruct interface as a model and not the native Date object. It's a simple data structure with 3 fields, but note that months start @@ -156,10 +157,10 @@

Input date parsing and formatting

NgbDateParserFormatter methods, as in custom date parser formatter example.

-
+ - +

Date selection and navigation are two different things. You might have a date selected in January, but August currently displayed. @@ -177,10 +178,10 @@

Input date parsing and formatting

-
+ - +

You can limit the dates available for navigation and selection using [minDate] and [maxDate] inputs. If you don't specify any of them, you'll have infinite @@ -195,10 +196,10 @@

Input date parsing and formatting

-
+ - +

You can completely replace how each date is rendered by providing a custom template and rendering anything you want inside. You'll get a date context available inside the template with info on whether current date is disabled, @@ -217,13 +218,14 @@

Input date parsing and formatting

let-date="date" in the template. See $implicit example in Angular documentation. -
+ - +

It is often useful to highlight a today's date in the calendar view or add a certain logic to it. Today's date is - the date returned by the NgbCalendar's getToday() + the date returned by the NgbCalendar's + getToday() method.

@@ -242,10 +244,10 @@

Input date parsing and formatting

-
+ - +

You can replace the content of the datepicker. Combined with the NgbDatepickerMonthView you can customize the layout of months as in the @@ -253,23 +255,24 @@

Input date parsing and formatting

-
+ - +

You can insert anything you want in a datepicker footer by providing a template.

-
+ - +

The datepicker model is a single date, however you still can implement range selection functionality. With (select) and (dateSelect) outputs you'll know which dates are being selected and with the [dayTemplate] input you can customize the way any particular date looks. If you want to use the NgbDatepickerInput, you can also tell the popup to stay open by tuning the - [autoClose] input. Check the range selection example + [autoClose] input. Check the + range selection example and the initial demo on this page for more details.

@@ -278,15 +281,16 @@

Input date parsing and formatting

NgbDatepicker inside of it. In this case we'll handle everything related to date selection and navigation for you and you can create a completely customized popup with any data model you want.

-
+ - +

Since the 2.0.0 release datepicker will use the application locale if it is present to get translations of weekdays and month names. The internal service that does translation is - called NgbDatepickerI18n and you could provide your own implementation if necessary. + called + NgbDatepickerI18n and you could provide your own implementation if necessary.

@@ -296,10 +300,10 @@

Input date parsing and formatting

month label is extracted under the ngb.datepicker.previous-month name.

-
+ - +

You can customize keyboard navigation as in the custom keyboard navigation example. The default keys are as @@ -358,4 +362,4 @@

Input date parsing and formatting

-
+ diff --git a/demo/src/app/components/datepicker/overview/datepicker-overview.component.ts b/demo/src/app/components/datepicker/overview/datepicker-overview.component.ts index 8fdcb84d78..a1f4735dce 100644 --- a/demo/src/app/components/datepicker/overview/datepicker-overview.component.ts +++ b/demo/src/app/components/datepicker/overview/datepicker-overview.component.ts @@ -1,25 +1,17 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, Input } from '@angular/core'; import { LIB_VERSIONS } from '../../../tokens'; import { Snippet } from '../../../services/snippet'; -import { NgbdDemoListService } from '../../../services/demo-list.service'; import { CodeComponent } from '../../../shared/code.component'; import { RouterLink } from '@angular/router'; import { NgbAlertModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbdDatepickerOverviewDemoComponent } from './demo/datepicker-overview-demo.component'; -import { NgbdOverviewSectionComponent } from '../../../shared/overview/overview-section.component'; -import { NgbdOverview } from '../../../shared/overview/overview'; +import { PageHeaderComponent } from '../../../shared/page-header.component'; @Component({ selector: 'ngbd-datepicker-overview', standalone: true, - imports: [ - CodeComponent, - RouterLink, - NgbdOverviewSectionComponent, - NgbAlertModule, - NgbdDatepickerOverviewDemoComponent, - ], + imports: [CodeComponent, RouterLink, NgbAlertModule, NgbdDatepickerOverviewDemoComponent, PageHeaderComponent], changeDetection: ChangeDetectionStrategy.OnPush, templateUrl: './datepicker-overview.component.html', host: { @@ -27,6 +19,9 @@ import { NgbdOverview } from '../../../shared/overview/overview'; }, }) export class NgbdDatepickerOverviewComponent { + bootstrapVersion = inject(LIB_VERSIONS).bootstrap; + @Input() overview: { fragment: string; title: string }; + snippets = { basic: Snippet({ lang: 'html', @@ -204,12 +199,4 @@ export class NgbdDatepickerOverviewComponent { `, }), }; - - bootstrapVersion = inject(LIB_VERSIONS).bootstrap; - - sections: NgbdOverview = {}; - - constructor(demoList: NgbdDemoListService) { - this.sections = demoList.getOverviewSections('datepicker'); - } } diff --git a/demo/src/app/components/dropdown/dropdown.routes.ts b/demo/src/app/components/dropdown/dropdown.routes.ts index 5b06cd54fe..cb76bb75d5 100644 --- a/demo/src/app/components/dropdown/dropdown.routes.ts +++ b/demo/src/app/components/dropdown/dropdown.routes.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdDropdownBasic } from './demos/basic/dropdown-basic'; import { NgbdDropdownConfig } from './demos/config/dropdown-config'; import { NgbdDropdownContainer } from './demos/container/dropdown-container'; @@ -11,59 +11,65 @@ import { NgbdDropdownNavbar } from './demos/navbar/dropdown-navbar'; import { NgbdDropdownSplit } from './demos/split/dropdown-split'; import { NgbdDropdownDisabled } from './demos/disabled/dropdown-disabled'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Dropdown', type: NgbdDropdownBasic, code: 'dropdown/demos/basic/dropdown-basic.ts', markup: 'dropdown/demos/basic/dropdown-basic.html', }, - manual: { + { + fragment: 'manual', title: 'Manual and custom triggers', type: NgbdDropdownManual, code: 'dropdown/demos/manual/dropdown-manual.ts', markup: 'dropdown/demos/manual/dropdown-manual.html', }, - split: { + { + fragment: 'split', title: 'Button groups and split buttons', type: NgbdDropdownSplit, code: 'dropdown/demos/split/dropdown-split.ts', markup: 'dropdown/demos/split/dropdown-split.html', }, - disabled: { + { + fragment: 'disabled', title: 'Disabled items', type: NgbdDropdownDisabled, code: 'dropdown/demos/disabled/dropdown-disabled.ts', markup: 'dropdown/demos/disabled/dropdown-disabled.html', }, - form: { + { + fragment: 'form', title: 'Mixed menu items and form', type: NgbdDropdownForm, code: 'dropdown/demos/form/dropdown-form.ts', markup: 'dropdown/demos/form/dropdown-form.html', }, - container: { + { + fragment: 'container', title: 'Container “body”', type: NgbdDropdownContainer, code: 'dropdown/demos/container/dropdown-container.ts', markup: 'dropdown/demos/container/dropdown-container.html', }, - navbar: { + { + fragment: 'navbar', title: 'Dynamic positioning in a navbar', type: NgbdDropdownNavbar, code: 'dropdown/demos/navbar/dropdown-navbar.ts', markup: 'dropdown/demos/navbar/dropdown-navbar.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of dropdowns', type: NgbdDropdownConfig, code: 'dropdown/demos/config/dropdown-config.ts', markup: 'dropdown/demos/config/dropdown-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -74,15 +80,8 @@ export const ROUTES: Routes = [ name: 'Dropdown', bootstrap: 'https://getbootstrap.com/docs/%version%/components/dropdowns/', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('dropdown', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/modal/modal.routes.ts b/demo/src/app/components/modal/modal.routes.ts index 0a2ce05d8c..99e362e3fd 100644 --- a/demo/src/app/components/modal/modal.routes.ts +++ b/demo/src/app/components/modal/modal.routes.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdModalBasic } from './demos/basic/modal-basic'; import { NgbdModalComponent } from './demos/component/modal-component'; import { NgbdModalConfig } from './demos/config/modal-config'; @@ -10,53 +10,58 @@ import { NgbdModalOptions } from './demos/options/modal-options'; import { NgbdModalUpdatableOptions } from './demos/updatable/modal-updatable-options'; import { NgbdModalStacked } from './demos/stacked/modal-stacked'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Modal with default options', type: NgbdModalBasic, code: 'modal/demos/basic/modal-basic.ts', markup: 'modal/demos/basic/modal-basic.html', }, - component: { + { + fragment: 'component', title: 'Components as content', type: NgbdModalComponent, code: 'modal/demos/component/modal-component.ts', markup: 'modal/demos/component/modal-component.html', }, - focus: { + { + fragment: 'focus', title: 'Focus management', type: NgbdModalFocus, code: 'modal/demos/focus/modal-focus.ts', markup: 'modal/demos/focus/modal-focus.html', }, - options: { + { + fragment: 'options', title: 'Modal with options', type: NgbdModalOptions, code: 'modal/demos/options/modal-options.ts', markup: 'modal/demos/options/modal-options.html', }, - updatable: { + { + fragment: 'updatable', title: 'Updatable options', type: NgbdModalUpdatableOptions, code: 'modal/demos/updatable/modal-updatable-options.ts', markup: 'modal/demos/updatable/modal-updatable-options.html', }, - stacked: { + { + fragment: 'stacked', title: 'Stacked modals', type: NgbdModalStacked, code: 'modal/demos/stacked/modal-stacked.ts', markup: 'modal/demos/stacked/modal-stacked.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of modals', type: NgbdModalConfig, code: 'modal/demos/config/modal-config.ts', markup: 'modal/demos/config/modal-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -67,15 +72,8 @@ export const ROUTES: Routes = [ name: 'Dropdown', bootstrap: 'https://getbootstrap.com/docs/%version%/components/modal/', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('modal', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/nav/nav.routes.ts b/demo/src/app/components/nav/nav.routes.ts index ffdac3ac0b..efeda382ca 100644 --- a/demo/src/app/components/nav/nav.routes.ts +++ b/demo/src/app/components/nav/nav.routes.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdNavBasic } from './demos/basic/nav-basic'; import { NgbdNavMarkup } from './demos/markup/nav-markup'; import { NgbdNavConfig } from './demos/config/nav-config'; @@ -12,8 +12,6 @@ import { NgbdNavKeep } from './demos/keep-content/nav-keep-content'; import { NgbdNavOverviewComponent } from './overview/nav-overview.component'; import { NgbdNavVertical } from './demos/vertical/nav-vertical'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; const OVERVIEW = { 'basic-usage': 'Basic Usage', @@ -22,56 +20,64 @@ const OVERVIEW = { 'keyboard-shortcuts': 'Keyboard shortcuts', }; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Basic navs', type: NgbdNavBasic, code: 'nav/demos/basic/nav-basic.ts', markup: 'nav/demos/basic/nav-basic.html', }, - markup: { + { + fragment: 'markup', title: 'Alternative markup', type: NgbdNavMarkup, code: 'nav/demos/markup/nav-markup.ts', markup: 'nav/demos/markup/nav-markup.html', }, - vertical: { + { + fragment: 'vertical', title: 'Vertical pills', type: NgbdNavVertical, code: 'nav/demos/vertical/nav-vertical.ts', markup: 'nav/demos/vertical/nav-vertical.html', }, - selection: { + { + fragment: 'selection', title: 'Selecting navs', type: NgbdNavSelection, code: 'nav/demos/selection/nav-selection.ts', markup: 'nav/demos/selection/nav-selection.html', }, - 'keep-content': { + { + fragment: 'keep-content', title: 'Keep content', type: NgbdNavKeep, code: 'nav/demos/keep-content/nav-keep-content.ts', markup: 'nav/demos/keep-content/nav-keep-content.html', }, - dynamic: { + { + fragment: 'dynamic', title: 'Dynamic navs', type: NgbdNavDynamic, code: 'nav/demos/dynamic/nav-dynamic.ts', markup: 'nav/demos/dynamic/nav-dynamic.html', }, - 'custom-style': { + { + fragment: 'custom-style', title: 'Custom style', type: NgbdNavCustomStyle, code: 'nav/demos/custom-style/nav-custom-style.ts', markup: 'nav/demos/custom-style/nav-custom-style.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of navs', type: NgbdNavConfig, code: 'nav/demos/config/nav-config.ts', markup: 'nav/demos/config/nav-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'overview' }, @@ -82,16 +88,17 @@ export const ROUTES: Routes = [ name: 'Nav', bootstrap: 'https://getbootstrap.com/docs/%version%/components/navs/', }, - providers: [ + children: [ { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('nav', DEMOS, OVERVIEW), + path: 'overview', + component: NgbdNavOverviewComponent, + data: { overview: OVERVIEW }, + }, + { + path: 'examples', + component: DemoListComponent, + data: { demos: DEMOS }, }, - ], - children: [ - { path: 'overview', component: NgbdNavOverviewComponent }, - { path: 'examples', component: NgbdExamplesPage }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/nav/overview/nav-overview.component.html b/demo/src/app/components/nav/overview/nav-overview.component.html index f98c4c4519..08523502f9 100644 --- a/demo/src/app/components/nav/overview/nav-overview.component.html +++ b/demo/src/app/components/nav/overview/nav-overview.component.html @@ -4,7 +4,7 @@

Nav directives will help you to build navigation components.

- +

Nav includes NgbNav, NgbNavItem, NgbNavLink, NgbNavContent directives and the NgbNavOutlet component. @@ -90,9 +90,9 @@

Selection / active nav

won't be raised in case of programmatic nav selection. It is not possible to select disabled tabs by clicking on them.

-
+ - + It is up to you to specify the nav type using bootstrap standard .nav-tabs or .nav-pills classes. Otherwise active nav will not be highlighted, @@ -126,9 +126,9 @@

Accessibility

-
+ - +

Router integration is simple: just use standard <router-outlet> component instead of ngbNavOutlet and add [routerLink] directives to nav links. @@ -144,9 +144,9 @@

Accessibility

and in your template:

-
+ - +

@@ -180,4 +180,4 @@

Accessibility

-
+ diff --git a/demo/src/app/components/nav/overview/nav-overview.component.ts b/demo/src/app/components/nav/overview/nav-overview.component.ts index e5022765ba..9715b366d3 100644 --- a/demo/src/app/components/nav/overview/nav-overview.component.ts +++ b/demo/src/app/components/nav/overview/nav-overview.component.ts @@ -1,25 +1,24 @@ -import { Component, inject } from '@angular/core'; +import { Component, inject, Input } from '@angular/core'; import { Snippet } from '../../../services/snippet'; -import { NgbdDemoListService } from '../../../services/demo-list.service'; import { LIB_VERSIONS } from '../../../tokens'; import { NgbAlertModule, NgbNavModule } from '@ng-bootstrap/ng-bootstrap'; import { CodeComponent } from '../../../shared/code.component'; import { RouterLink } from '@angular/router'; import { NgbdApiDocsBadge } from '../../../shared/api-docs'; -import { NgbdOverviewSectionComponent } from '../../../shared/overview/overview-section.component'; -import { NgbdOverview } from '../../../shared/overview/overview'; +import { PageHeaderComponent } from '../../../shared/page-header.component'; @Component({ selector: 'ngbd-nav-overview', standalone: true, - imports: [NgbNavModule, NgbAlertModule, NgbdOverviewSectionComponent, CodeComponent, RouterLink, NgbdApiDocsBadge], + imports: [NgbNavModule, NgbAlertModule, CodeComponent, RouterLink, NgbdApiDocsBadge, PageHeaderComponent], templateUrl: './nav-overview.component.html', host: { '[class.overview]': 'true' }, }) export class NgbdNavOverviewComponent { bootstrapVersion = inject(LIB_VERSIONS).bootstrap; + @Input() overview: { fragment: string; title: string }; BASIC = Snippet({ lang: 'html', @@ -110,10 +109,4 @@ export class NgbdNavOverviewComponent { constructor(public route: ActivatedRoute) {} `, }); - - sections: NgbdOverview = {}; - - constructor(demoList: NgbdDemoListService) { - this.sections = demoList.getOverviewSections('nav'); - } } diff --git a/demo/src/app/components/offcanvas/offcanvas.routes.ts b/demo/src/app/components/offcanvas/offcanvas.routes.ts index 866e334f24..edea80a2fb 100644 --- a/demo/src/app/components/offcanvas/offcanvas.routes.ts +++ b/demo/src/app/components/offcanvas/offcanvas.routes.ts @@ -1,48 +1,51 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdOffcanvasBasic } from './demos/basic/offcanvas-basic'; import { NgbdOffcanvasComponent } from './demos/component/offcanvas-component'; import { NgbdOffcanvasOptions } from './demos/options/offcanvas-options'; import { NgbdOffcanvasFocus } from './demos/focus/offcanvas-focus'; import { NgbdOffcanvasConfig } from './demos/config/offcanvas-config'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Basic offcanvas', type: NgbdOffcanvasBasic, code: 'offcanvas/demos/basic/offcanvas-basic.ts', markup: 'offcanvas/demos/basic/offcanvas-basic.html', }, - component: { + { + fragment: 'component', title: 'Components as content', type: NgbdOffcanvasComponent, code: 'offcanvas/demos/component/offcanvas-component.ts', markup: 'offcanvas/demos/component/offcanvas-component.html', }, - options: { + { + fragment: 'options', title: 'Offcanvas options', type: NgbdOffcanvasOptions, code: 'offcanvas/demos/options/offcanvas-options.ts', markup: 'offcanvas/demos/options/offcanvas-options.html', }, - focus: { + { + fragment: 'focus', title: 'Focus management', type: NgbdOffcanvasFocus, code: 'offcanvas/demos/focus/offcanvas-focus.ts', markup: 'offcanvas/demos/focus/offcanvas-focus.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of Offcanvas', type: NgbdOffcanvasConfig, code: 'offcanvas/demos/config/offcanvas-config.ts', markup: 'offcanvas/demos/config/offcanvas-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -53,15 +56,8 @@ export const ROUTES: Routes = [ name: 'Offcanvas', bootstrap: 'https://getbootstrap.com/docs/%version%/components/offcanvas/', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('offcanvas', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/pagination/overview/pagination-overview.component.html b/demo/src/app/components/pagination/overview/pagination-overview.component.html index 45bc643e50..fc7846f225 100644 --- a/demo/src/app/components/pagination/overview/pagination-overview.component.html +++ b/demo/src/app/components/pagination/overview/pagination-overview.component.html @@ -3,7 +3,7 @@ to split your data collection into pages yourself.

- +

In order to properly operate a pagination behaviour, there are 3 important notions you have to be familiar with, which are actually available as @Input() on the widget: @@ -43,9 +43,9 @@

Filtering and sorting

>, you don't need to reimplement dedicated pipes for that purpose. Recommendation is to move filtering and sorting logic into the component itself where some property getters could be exposed.

-
+ - +

It is possible to customize what exactly is displayed in each pagination link and there are several ways of doing it. @@ -89,4 +89,4 @@

Using templates

Also see the Customization example for a live version.

-
+ diff --git a/demo/src/app/components/pagination/overview/pagination-overview.component.ts b/demo/src/app/components/pagination/overview/pagination-overview.component.ts index 622fea5b1f..3d9e0a5b16 100644 --- a/demo/src/app/components/pagination/overview/pagination-overview.component.ts +++ b/demo/src/app/components/pagination/overview/pagination-overview.component.ts @@ -1,23 +1,23 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { Snippet } from '../../../services/snippet'; -import { NgbdDemoListService } from '../../../services/demo-list.service'; import { CodeComponent } from '../../../shared/code.component'; import { NgbAlertModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbdApiDocsBadge } from '../../../shared/api-docs'; import { RouterLink } from '@angular/router'; -import { NgbdOverviewSectionComponent } from '../../../shared/overview/overview-section.component'; -import { NgbdOverview } from '../../../shared/overview/overview'; +import { PageHeaderComponent } from '../../../shared/page-header.component'; @Component({ selector: 'ngbd-pagination-overview', standalone: true, - imports: [NgbdOverviewSectionComponent, CodeComponent, NgbAlertModule, NgbdApiDocsBadge, RouterLink], + imports: [CodeComponent, NgbAlertModule, NgbdApiDocsBadge, RouterLink, PageHeaderComponent], templateUrl: './pagination-overview.component.html', changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class.overview]': 'true' }, }) export class NgbdPaginationOverviewComponent { + @Input() overview: { fragment: string; title: string }; + NGFOR = Snippet({ lang: 'html', code: ` @@ -79,10 +79,4 @@ export class NgbdPaginationOverviewComponent { `, }); - - sections: NgbdOverview = {}; - - constructor(demoList: NgbdDemoListService) { - this.sections = demoList.getOverviewSections('pagination'); - } } diff --git a/demo/src/app/components/pagination/pagination.routes.ts b/demo/src/app/components/pagination/pagination.routes.ts index baeb13ae50..b3df18612c 100644 --- a/demo/src/app/components/pagination/pagination.routes.ts +++ b/demo/src/app/components/pagination/pagination.routes.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdPaginationAdvanced } from './demos/advanced/pagination-advanced'; import { NgbdPaginationBasic } from './demos/basic/pagination-basic'; import { NgbdPaginationConfig } from './demos/config/pagination-config'; @@ -11,58 +11,63 @@ import { NgbdPaginationJustify } from './demos/justify/pagination-justify'; import { NgbdPaginationSize } from './demos/size/pagination-size'; import { NgbdPaginationOverviewComponent } from './overview/pagination-overview.component'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; const OVERVIEW = { 'basic-usage': 'Basic Usage', customization: 'Customization', }; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Basic pagination', type: NgbdPaginationBasic, code: 'pagination/demos/basic/pagination-basic.ts', markup: 'pagination/demos/basic/pagination-basic.html', }, - advanced: { + { + fragment: 'advanced', title: 'Advanced pagination', type: NgbdPaginationAdvanced, code: 'pagination/demos/advanced/pagination-advanced.ts', markup: 'pagination/demos/advanced/pagination-advanced.html', }, - customization: { + { + fragment: 'customization', title: 'Custom links and pages', type: NgbdPaginationCustomization, code: 'pagination/demos/customization/pagination-customization.ts', markup: 'pagination/demos/customization/pagination-customization.html', }, - size: { + { + fragment: 'size', title: 'Pagination size', type: NgbdPaginationSize, code: 'pagination/demos/size/pagination-size.ts', markup: 'pagination/demos/size/pagination-size.html', }, - justify: { + { + fragment: 'justify', title: 'Pagination alignment', type: NgbdPaginationJustify, code: 'pagination/demos/justify/pagination-justify.ts', markup: 'pagination/demos/justify/pagination-justify.html', }, - disabled: { + { + fragment: 'disabled', title: 'Disabled pagination', type: NgbdPaginationDisabled, code: 'pagination/demos/disabled/pagination-disabled.ts', markup: 'pagination/demos/disabled/pagination-disabled.html', }, - config: { + { + fragment: 'config', title: 'Global configuration', type: NgbdPaginationConfig, code: 'pagination/demos/config/pagination-config.ts', markup: 'pagination/demos/config/pagination-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'overview' }, @@ -73,16 +78,17 @@ export const ROUTES: Routes = [ name: 'Pagination', bootstrap: 'https://getbootstrap.com/docs/%version%/components/pagination/', }, - providers: [ + children: [ { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('pagination', DEMOS, OVERVIEW), + path: 'overview', + component: NgbdPaginationOverviewComponent, + data: { overview: OVERVIEW }, + }, + { + path: 'examples', + component: DemoListComponent, + data: { demos: DEMOS }, }, - ], - children: [ - { path: 'overview', component: NgbdPaginationOverviewComponent }, - { path: 'examples', component: NgbdExamplesPage }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/popover/popover.routes.ts b/demo/src/app/components/popover/popover.routes.ts index cab02c221e..e82a1e094b 100644 --- a/demo/src/app/components/popover/popover.routes.ts +++ b/demo/src/app/components/popover/popover.routes.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdPopoverAutoclose } from './demos/autoclose/popover-autoclose'; import { NgbdPopoverBasic } from './demos/basic/popover-basic'; import { NgbdPopoverConfig } from './demos/config/popover-config'; @@ -15,83 +15,93 @@ import { NgbdPopoverVisibility } from './demos/visibility/popover-visibility'; import { NgbdPopoverTarget } from './demos/custom-target/popover-target'; import { Routes } from '@angular/router'; import { NgbdPopoverOptions } from './demos/options/popover-options'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Quick and easy popovers', type: NgbdPopoverBasic, code: 'popover/demos/basic/popover-basic.ts', markup: 'popover/demos/basic/popover-basic.html', }, - tplcontent: { + { + fragment: 'tplcontent', title: 'HTML and bindings in popovers', type: NgbdPopoverTplcontent, code: 'popover/demos/tplcontent/popover-tplcontent.ts', markup: 'popover/demos/tplcontent/popover-tplcontent.html', }, - triggers: { + { + fragment: 'triggers', title: 'Custom and manual triggers', type: NgbdPopoverTriggers, code: 'popover/demos/triggers/popover-triggers.ts', markup: 'popover/demos/triggers/popover-triggers.html', }, - autoclose: { + { + fragment: 'autoclose', title: 'Automatic closing with keyboard and mouse', type: NgbdPopoverAutoclose, code: 'popover/demos/autoclose/popover-autoclose.ts', markup: 'popover/demos/autoclose/popover-autoclose.html', }, - tplwithcontext: { + { + fragment: 'tplwithcontext', title: 'Context and manual triggers', type: NgbdPopoverTplwithcontext, code: 'popover/demos/tplwithcontext/popover-tplwithcontext.ts', markup: 'popover/demos/tplwithcontext/popover-tplwithcontext.html', }, - target: { + { + fragment: 'target', title: 'Custom target', type: NgbdPopoverTarget, code: 'popover/demos/custom-target/popover-target.ts', markup: 'popover/demos/custom-target/popover-target.html', }, - delay: { + { + fragment: 'delay', title: 'Open and close delays', type: NgbdPopoverDelay, code: 'popover/demos/delay/popover-delay.ts', markup: 'popover/demos/delay/popover-delay.html', }, - visibility: { + { + fragment: 'visibility', title: 'Popover visibility events', type: NgbdPopoverVisibility, code: 'popover/demos/visibility/popover-visibility.ts', markup: 'popover/demos/visibility/popover-visibility.html', }, - container: { + { + fragment: 'container', title: 'Append popover in the body', type: NgbdPopoverContainer, code: 'popover/demos/container/popover-container.ts', markup: 'popover/demos/container/popover-container.html', }, - customclass: { + { + fragment: 'customclass', title: 'Popover with custom class', type: NgbdPopoverCustomclass, code: 'popover/demos/customclass/popover-customclass.ts', markup: 'popover/demos/customclass/popover-customclass.html', }, - options: { + { + fragment: 'options', title: 'Popper options', type: NgbdPopoverOptions, code: 'popover/demos/options/popover-options.ts', markup: 'popover/demos/options/popover-options.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of popovers', type: NgbdPopoverConfig, code: 'popover/demos/config/popover-config.ts', markup: 'popover/demos/config/popover-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -102,15 +112,8 @@ export const ROUTES: Routes = [ name: 'Popover', bootstrap: 'https://getbootstrap.com/docs/%version%/components/popovers/', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('popover', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/progressbar/progressbar.routes.ts b/demo/src/app/components/progressbar/progressbar.routes.ts index 8f7db4fa71..07fda3bbe6 100644 --- a/demo/src/app/components/progressbar/progressbar.routes.ts +++ b/demo/src/app/components/progressbar/progressbar.routes.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdProgressbarBasic } from './demos/basic/progressbar-basic'; import { NgbdProgressbarConfig } from './demos/config/progressbar-config'; import { NgbdProgressbarHeight } from './demos/height/progressbar-height'; @@ -10,53 +10,58 @@ import { NgbdProgressbarShowvalue } from './demos/showvalue/progressbar-showvalu import { NgbdProgressbarStriped } from './demos/striped/progressbar-striped'; import { NgbdProgressbarTextTypes } from './demos/texttypes/progressbar-texttypes'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Contextual progress bars', type: NgbdProgressbarBasic, code: 'progressbar/demos/basic/progressbar-basic.ts', markup: 'progressbar/demos/basic/progressbar-basic.html', }, - texttypes: { + { + fragment: 'texttypes', title: 'Contextual text progress bars', type: NgbdProgressbarTextTypes, code: 'progressbar/demos/texttypes/progressbar-texttypes.ts', markup: 'progressbar/demos/texttypes/progressbar-texttypes.html', }, - showvalue: { + { + fragment: 'showvalue', title: 'Progress bars with current value labels', type: NgbdProgressbarShowvalue, code: 'progressbar/demos/showvalue/progressbar-showvalue.ts', markup: 'progressbar/demos/showvalue/progressbar-showvalue.html', }, - striped: { + { + fragment: 'striped', title: 'Striped progress bars', type: NgbdProgressbarStriped, code: 'progressbar/demos/striped/progressbar-striped.ts', markup: 'progressbar/demos/striped/progressbar-striped.html', }, - labels: { + { + fragment: 'labels', title: 'Progress bars with custom labels', type: NgbdProgressbarLabels, code: 'progressbar/demos/labels/progressbar-labels.ts', markup: 'progressbar/demos/labels/progressbar-labels.html', }, - height: { + { + fragment: 'height', title: 'Progress bars with height', type: NgbdProgressbarHeight, code: 'progressbar/demos/height/progressbar-height.ts', markup: 'progressbar/demos/height/progressbar-height.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of progress bars', type: NgbdProgressbarConfig, code: 'progressbar/demos/config/progressbar-config.ts', markup: 'progressbar/demos/config/progressbar-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -67,15 +72,8 @@ export const ROUTES: Routes = [ name: 'Progressbar', bootstrap: 'https://getbootstrap.com/docs/%version%/components/progress/', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('progressbar', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/rating/rating.routes.ts b/demo/src/app/components/rating/rating.routes.ts index 4d4c46efca..8d3191e4f0 100644 --- a/demo/src/app/components/rating/rating.routes.ts +++ b/demo/src/app/components/rating/rating.routes.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdRatingBasic } from './demos/basic/rating-basic'; import { NgbdRatingConfig } from './demos/config/rating-config'; import { NgbdRatingDecimal } from './demos/decimal/rating-decimal'; @@ -9,47 +9,51 @@ import { NgbdRatingEvents } from './demos/events/rating-events'; import { NgbdRatingForm } from './demos/form/rating-form'; import { NgbdRatingTemplate } from './demos/template/rating-template'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Basic demo', type: NgbdRatingBasic, code: 'rating/demos/basic/rating-basic.ts', markup: 'rating/demos/basic/rating-basic.html', }, - events: { + { + fragment: 'events', title: 'Events and readonly ratings', type: NgbdRatingEvents, code: 'rating/demos/events/rating-events.ts', markup: 'rating/demos/events/rating-events.html', }, - template: { + { + fragment: 'template', title: 'Custom star template', type: NgbdRatingTemplate, code: 'rating/demos/template/rating-template.ts', markup: 'rating/demos/template/rating-template.html', }, - decimal: { + { + fragment: 'decimal', title: 'Custom decimal rating', type: NgbdRatingDecimal, code: 'rating/demos/decimal/rating-decimal.ts', markup: 'rating/demos/decimal/rating-decimal.html', }, - form: { + { + fragment: 'form', title: 'Form integration', type: NgbdRatingForm, code: 'rating/demos/form/rating-form.ts', markup: 'rating/demos/form/rating-form.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of ratings', type: NgbdRatingConfig, code: 'rating/demos/config/rating-config.ts', markup: 'rating/demos/config/rating-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -59,15 +63,8 @@ export const ROUTES: Routes = [ data: { name: 'Rating', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('rating', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/scrollspy/overview/scrollspy-overview.component.html b/demo/src/app/components/scrollspy/overview/scrollspy-overview.component.html index 5cd33e7619..fc10a96c7f 100644 --- a/demo/src/app/components/scrollspy/overview/scrollspy-overview.component.html +++ b/demo/src/app/components/scrollspy/overview/scrollspy-overview.component.html @@ -7,7 +7,7 @@

and get notified when a part of it is scrolled into or out of the viewport.

- +

The core scrollspy implementation is a NgbScrollSpyService that is based on an @@ -34,9 +34,9 @@

You can use the service together with the routerLink directive and its [fragment] input, or you can force the scrollspy to get to a specific fragment via the .scrollTo() method.

- + - +

The directive will help you to setup the scrollspy service instance on a specific container. It is merely a syntactic sugar around the service that will start and add fragments automatically, as well as clean everything up @@ -52,9 +52,9 @@

NgbScrollSpy API for all available inputs and outputs.

- + - +

There are also two helper directives: NgbScrollSpyMenu and NgbScrollSpyItem. They will highlight the active item in a menu, nav or any custom list. @@ -93,9 +93,9 @@

Hierarchical menus

For more details, please see the related remo

-
+ - +

If you want to customize the IntersectionObserver you can pass rootMargin and threshold options when starting the service. @@ -121,4 +121,4 @@

Hierarchical menus

-
+ diff --git a/demo/src/app/components/scrollspy/overview/scrollspy-overview.component.ts b/demo/src/app/components/scrollspy/overview/scrollspy-overview.component.ts index 15a0c02707..cde2c96d67 100644 --- a/demo/src/app/components/scrollspy/overview/scrollspy-overview.component.ts +++ b/demo/src/app/components/scrollspy/overview/scrollspy-overview.component.ts @@ -1,29 +1,22 @@ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { Snippet } from '../../../services/snippet'; -import { NgbdDemoListService } from '../../../services/demo-list.service'; import { NgbAlertModule, NgbScrollSpyModule } from '@ng-bootstrap/ng-bootstrap'; import { CodeComponent } from '../../../shared/code.component'; import { RouterLink } from '@angular/router'; import { NgbdApiDocsBadge } from '../../../shared/api-docs'; -import { NgbdOverviewSectionComponent } from '../../../shared/overview/overview-section.component'; -import { NgbdOverview } from '../../../shared/overview/overview'; +import { PageHeaderComponent } from '../../../shared/page-header.component'; @Component({ selector: 'ngbd-scrollspy-overview', standalone: true, - imports: [ - NgbAlertModule, - NgbScrollSpyModule, - NgbdOverviewSectionComponent, - CodeComponent, - RouterLink, - NgbdApiDocsBadge, - ], + imports: [NgbAlertModule, NgbScrollSpyModule, CodeComponent, RouterLink, NgbdApiDocsBadge, PageHeaderComponent], templateUrl: './scrollspy-overview.component.html', host: { '[class.overview]': 'true' }, }) export class NgbdScrollSpyOverviewComponent { + @Input() overview: { fragment: string; title: string }; + SERVICE = Snippet({ lang: 'ts', code: ` @@ -120,10 +113,4 @@ export class NgbdScrollSpyOverviewComponent {
{{ spy.active }}
// 'one' `, }); - - sections: NgbdOverview = {}; - - constructor(demoList: NgbdDemoListService) { - this.sections = demoList.getOverviewSections('scrollspy'); - } } diff --git a/demo/src/app/components/scrollspy/scrollspy.routes.ts b/demo/src/app/components/scrollspy/scrollspy.routes.ts index bb3b1f0eae..5fb3b3d0b6 100644 --- a/demo/src/app/components/scrollspy/scrollspy.routes.ts +++ b/demo/src/app/components/scrollspy/scrollspy.routes.ts @@ -1,11 +1,9 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdScrollSpyOverviewComponent } from './overview/scrollspy-overview.component'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; import { NgbdScrollSpyBasic } from './demos/basic/scrollspy-basic'; import { NgbdScrollSpyNavbar } from './demos/navbar/scrollspy-navbar'; import { NgbdScrollSpyItems } from './demos/items/scrollspy-items'; @@ -19,38 +17,43 @@ const OVERVIEW = { customization: 'Customization', }; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Basic', type: NgbdScrollSpyBasic, code: 'scrollspy/demos/basic/scrollspy-basic.ts', markup: 'scrollspy/demos/basic/scrollspy-basic.html', }, - items: { + { + fragment: 'items', title: 'Menu items', type: NgbdScrollSpyItems, code: 'scrollspy/demos/items/scrollspy-items.ts', markup: 'scrollspy/demos/items/scrollspy-items.html', }, - service: { + { + fragment: 'service', title: 'Service', type: NgbdScrollSpyService, code: 'scrollspy/demos/service/scrollspy-service.ts', markup: 'scrollspy/demos/service/scrollspy-service.html', }, - nested: { + { + fragment: 'nested', title: 'Nested items', type: NgbdScrollSpyNested, code: 'scrollspy/demos/nested/scrollspy-nested.ts', markup: 'scrollspy/demos/nested/scrollspy-nested.html', }, - navbar: { + { + fragment: 'navbar', title: 'Navbar', type: NgbdScrollSpyNavbar, code: 'scrollspy/demos/navbar/scrollspy-navbar.ts', markup: 'scrollspy/demos/navbar/scrollspy-navbar.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'overview' }, @@ -61,16 +64,17 @@ export const ROUTES: Routes = [ name: 'Scrollspy', bootstrap: 'https://getbootstrap.com/docs/%version%/components/scrollspy/', }, - providers: [ + children: [ { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('scrollspy', DEMOS, OVERVIEW), + path: 'overview', + component: NgbdScrollSpyOverviewComponent, + data: { overview: OVERVIEW }, + }, + { + path: 'examples', + component: DemoListComponent, + data: { demos: DEMOS }, }, - ], - children: [ - { path: 'overview', component: NgbdScrollSpyOverviewComponent }, - { path: 'examples', component: NgbdExamplesPage }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/table/overview/table-overview.component.html b/demo/src/app/components/table/overview/table-overview.component.html index 34238f7b8d..a488f76fa0 100644 --- a/demo/src/app/components/table/overview/table-overview.component.html +++ b/demo/src/app/components/table/overview/table-overview.component.html @@ -15,7 +15,7 @@ GitHub. - +

Most importantly, there are way too many different use cases and options for such a complex component. Instead of building a monster-of-a-widget with hundreds of options and customizations, we would encourage you to use @@ -36,9 +36,9 @@

  • doesn't bloat your resulting bundle size by bringing 3rd party dependencies
  • doesn't pretend to be an Angular library by wrapping something else
  • -
    + - +

    Having said that, we decided to give you some simple examples of common table features. Take a look at them for the inspiration and maybe even use them as a starting point. @@ -64,4 +64,4 @@ custom delay for the data fetch. - + diff --git a/demo/src/app/components/table/overview/table-overview.component.ts b/demo/src/app/components/table/overview/table-overview.component.ts index c1e07eebb7..ef08155f62 100644 --- a/demo/src/app/components/table/overview/table-overview.component.ts +++ b/demo/src/app/components/table/overview/table-overview.component.ts @@ -1,17 +1,15 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, Input } from '@angular/core'; import { NgbAlertModule } from '@ng-bootstrap/ng-bootstrap'; import { LIB_VERSIONS } from '../../../tokens'; -import { NgbdDemoListService } from '../../../services/demo-list.service'; import { RouterLink } from '@angular/router'; import { NgbdTableOverviewDemo } from './demo/table-overview-demo.component'; -import { NgbdOverviewSectionComponent } from '../../../shared/overview/overview-section.component'; -import { NgbdOverview } from '../../../shared/overview/overview'; +import { PageHeaderComponent } from '../../../shared/page-header.component'; @Component({ selector: 'ngbd-table-overview', standalone: true, - imports: [NgbAlertModule, NgbdOverviewSectionComponent, RouterLink, NgbdTableOverviewDemo], + imports: [NgbAlertModule, RouterLink, NgbdTableOverviewDemo, PageHeaderComponent], changeDetection: ChangeDetectionStrategy.OnPush, templateUrl: './table-overview.component.html', host: { @@ -19,11 +17,6 @@ import { NgbdOverview } from '../../../shared/overview/overview'; }, }) export class NgbdTableOverviewComponent { + @Input() overview: { fragment: string; title: string }; bootstrapVersion = inject(LIB_VERSIONS).bootstrap; - - sections: NgbdOverview = {}; - - constructor(demoList: NgbdDemoListService) { - this.sections = demoList.getOverviewSections('table'); - } } diff --git a/demo/src/app/components/table/table.routes.ts b/demo/src/app/components/table/table.routes.ts index cc93670f5a..f266bec067 100644 --- a/demo/src/app/components/table/table.routes.ts +++ b/demo/src/app/components/table/table.routes.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdTableBasic } from './demos/basic/table-basic'; import { NgbdTableComplete } from './demos/complete/table-complete'; import { NgbdTableFiltering } from './demos/filtering/table-filtering'; @@ -8,16 +8,15 @@ import { NgbdTablePagination } from './demos/pagination/table-pagination'; import { NgbdTableSortable } from './demos/sortable/table-sortable'; import { NgbdTableOverviewComponent } from './overview/table-overview.component'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; const OVERVIEW = { 'why-not': 'Why not?', examples: 'Code examples', }; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Basic table', type: NgbdTableBasic, files: [ @@ -31,7 +30,8 @@ const DEMOS = { }, ], }, - sortable: { + { + fragment: 'sortable', title: 'Sortable table', type: NgbdTableSortable, files: [ @@ -45,7 +45,8 @@ const DEMOS = { }, ], }, - filtering: { + { + fragment: 'filtering', title: 'Search and filtering', type: NgbdTableFiltering, files: [ @@ -59,7 +60,8 @@ const DEMOS = { }, ], }, - pagination: { + { + fragment: 'pagination', title: 'Pagination', type: NgbdTablePagination, files: [ @@ -73,7 +75,8 @@ const DEMOS = { }, ], }, - complete: { + { + fragment: 'complete', title: 'Complete example', type: NgbdTableComplete, files: [ @@ -103,7 +106,7 @@ const DEMOS = { }, ], }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'overview' }, @@ -113,16 +116,17 @@ export const ROUTES: Routes = [ data: { name: 'Table', }, - providers: [ + children: [ { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('table', DEMOS, OVERVIEW), + path: 'overview', + component: NgbdTableOverviewComponent, + data: { overview: OVERVIEW }, + }, + { + path: 'examples', + component: DemoListComponent, + data: { demos: DEMOS }, }, - ], - children: [ - { path: 'overview', component: NgbdTableOverviewComponent }, - { path: 'examples', component: NgbdExamplesPage }, ], }, ]; diff --git a/demo/src/app/components/timepicker/timepicker.routes.ts b/demo/src/app/components/timepicker/timepicker.routes.ts index 7d666eee47..a74c347e16 100644 --- a/demo/src/app/components/timepicker/timepicker.routes.ts +++ b/demo/src/app/components/timepicker/timepicker.routes.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdTimepickerAdapter } from './demos/adapter/timepicker-adapter'; import { NgbdTimepickerBasic } from './demos/basic/timepicker-basic'; import { NgbdTimepickerConfig } from './demos/config/timepicker-config'; @@ -12,65 +12,72 @@ import { NgbdTimepickerSteps } from './demos/steps/timepicker-steps'; import { NgbdTimepickerValidation } from './demos/validation/timepicker-validation'; import { NgbdTimepickerI18n } from './demos/i18n/timepicker-i18n'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Timepicker', type: NgbdTimepickerBasic, code: 'timepicker/demos/basic/timepicker-basic.ts', markup: 'timepicker/demos/basic/timepicker-basic.html', }, - meridian: { + { + fragment: 'meridian', title: 'Meridian', type: NgbdTimepickerMeridian, code: 'timepicker/demos/meridian/timepicker-meridian.ts', markup: 'timepicker/demos/meridian/timepicker-meridian.html', }, - seconds: { + { + fragment: 'seconds', title: 'Seconds', type: NgbdTimepickerSeconds, code: 'timepicker/demos/seconds/timepicker-seconds.ts', markup: 'timepicker/demos/seconds/timepicker-seconds.html', }, - spinners: { + { + fragment: 'spinners', title: 'Spinners', type: NgbdTimepickerSpinners, code: 'timepicker/demos/spinners/timepicker-spinners.ts', markup: 'timepicker/demos/spinners/timepicker-spinners.html', }, - steps: { + { + fragment: 'steps', title: 'Custom steps', type: NgbdTimepickerSteps, code: 'timepicker/demos/steps/timepicker-steps.ts', markup: 'timepicker/demos/steps/timepicker-steps.html', }, - validation: { + { + fragment: 'validation', title: 'Custom validation', type: NgbdTimepickerValidation, code: 'timepicker/demos/validation/timepicker-validation.ts', markup: 'timepicker/demos/validation/timepicker-validation.html', }, - adapter: { + { + fragment: 'adapter', title: 'Custom time adapter', type: NgbdTimepickerAdapter, code: 'timepicker/demos/adapter/timepicker-adapter.ts', markup: 'timepicker/demos/adapter/timepicker-adapter.html', }, - i18n: { + { + fragment: 'i18n', title: 'Internationalization of timepickers', type: NgbdTimepickerI18n, code: 'timepicker/demos/i18n/timepicker-i18n.ts', markup: 'timepicker/demos/i18n/timepicker-i18n.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of timepickers', type: NgbdTimepickerConfig, code: 'timepicker/demos/config/timepicker-config.ts', markup: 'timepicker/demos/config/timepicker-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -80,15 +87,8 @@ export const ROUTES: Routes = [ data: { name: 'Timepicker', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('timepicker', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/toast/overview/toast-overview.component.html b/demo/src/app/components/toast/overview/toast-overview.component.html index 39318c3b1e..3d8b3e3d29 100644 --- a/demo/src/app/components/toast/overview/toast-overview.component.html +++ b/demo/src/app/components/toast/overview/toast-overview.component.html @@ -3,7 +3,7 @@ Goal is to mimic the push notifications available both on mobile and desktop operating systems.

    - +

    NgbToast component allows you to only render the corresponding markup. Use it in one of your templates, and you are done. It will render a toast. @@ -25,9 +25,9 @@ application environment.

    -
    +
    - +

    Let's take the opportunity to demonstrate how to simply build a global toast management service.

    TLDR; @@ -130,4 +130,4 @@

    2. Toast container component

    Click here to see an example a bit more advanced of this how-to.

    -
    + diff --git a/demo/src/app/components/toast/overview/toast-overview.component.ts b/demo/src/app/components/toast/overview/toast-overview.component.ts index e928404019..688c1004e2 100644 --- a/demo/src/app/components/toast/overview/toast-overview.component.ts +++ b/demo/src/app/components/toast/overview/toast-overview.component.ts @@ -1,24 +1,23 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, Input } from '@angular/core'; import { Snippet } from '../../../services/snippet'; -import { NgbdDemoListService } from '../../../services/demo-list.service'; import { LIB_VERSIONS } from '../../../tokens'; import { RouterLink } from '@angular/router'; import { CodeComponent } from '../../../shared/code.component'; import { NgbAlertModule, NgbNavModule } from '@ng-bootstrap/ng-bootstrap'; -import { NgbdOverviewSectionComponent } from '../../../shared/overview/overview-section.component'; -import { NgbdOverview } from '../../../shared/overview/overview'; +import { PageHeaderComponent } from '../../../shared/page-header.component'; @Component({ selector: 'ngbd-toast-overview', standalone: true, - imports: [NgbAlertModule, NgbNavModule, NgbdOverviewSectionComponent, RouterLink, CodeComponent], + imports: [NgbAlertModule, NgbNavModule, RouterLink, CodeComponent, PageHeaderComponent], templateUrl: './toast-overview.component.html', changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class.overview]': 'true' }, }) export class NgbdToastOverviewComponent { bootstrapVersion = inject(LIB_VERSIONS).bootstrap; + @Input() overview: { fragment: string; title: string }; TOAST_INLINE_BASIC = Snippet({ lang: 'html', @@ -111,10 +110,4 @@ export class NgbdToastOverviewComponent { `, }); - - sections: NgbdOverview = {}; - - constructor(demoList: NgbdDemoListService) { - this.sections = demoList.getOverviewSections('toast'); - } } diff --git a/demo/src/app/components/toast/toast.routes.ts b/demo/src/app/components/toast/toast.routes.ts index 1cb174b789..d353f2a707 100644 --- a/demo/src/app/components/toast/toast.routes.ts +++ b/demo/src/app/components/toast/toast.routes.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdToastCloseable } from './demos/closeable/toast-closeable'; import { NgbdToastCustomHeader } from './demos/custom-header/toast-custom-header'; import { NgbdToastGlobal } from './demos/howto-global/toast-global.component'; @@ -9,40 +9,43 @@ import { NgbdToastInline } from './demos/inline/toast-inline'; import { NgbdToastPreventAutohide } from './demos/prevent-autohide/toast-prevent-autohide'; import { NgbdToastOverviewComponent } from './overview/toast-overview.component'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; const OVERVIEW = { 'inline-usage': 'Declarative usage', 'toast-service': 'Building a toast management service', }; -const DEMOS = { - inline: { +const DEMOS = [ + { + fragment: 'inline', title: 'Declarative inline usage', type: NgbdToastInline, code: 'toast/demos/inline/toast-inline.ts', markup: 'toast/demos/inline/toast-inline.html', }, - 'custom-header': { + { + fragment: 'custom-header', title: 'Using a Template as header', type: NgbdToastCustomHeader, code: 'toast/demos/custom-header/toast-custom-header.ts', markup: 'toast/demos/custom-header/toast-custom-header.html', }, - closeable: { + { + fragment: 'closeable', title: 'Closeable toast', type: NgbdToastCloseable, code: 'toast/demos/closeable/toast-closeable.ts', markup: 'toast/demos/closeable/toast-closeable.html', }, - 'prevent-autohide': { + { + fragment: 'prevent-autohide', title: 'Prevent autohide on mouseover', type: NgbdToastPreventAutohide, code: 'toast/demos/prevent-autohide/toast-prevent-autohide.ts', markup: 'toast/demos/prevent-autohide/toast-prevent-autohide.html', }, - 'howto-global': { + { + fragment: 'howto-global', title: 'Toast management service', type: NgbdToastGlobal, files: [ @@ -64,7 +67,7 @@ const DEMOS = { }, ], }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'overview' }, @@ -75,16 +78,17 @@ export const ROUTES: Routes = [ name: 'Toast', bootstrap: `https://getbootstrap.com/docs/%version%/components/toasts/`, }, - providers: [ + children: [ { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('toast', DEMOS, OVERVIEW), + path: 'overview', + component: NgbdToastOverviewComponent, + data: { overview: OVERVIEW }, + }, + { + path: 'examples', + component: DemoListComponent, + data: { demos: DEMOS }, }, - ], - children: [ - { path: 'overview', component: NgbdToastOverviewComponent }, - { path: 'examples', component: NgbdExamplesPage }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/tooltip/tooltip.routes.ts b/demo/src/app/components/tooltip/tooltip.routes.ts index 4c7c78121b..d15c9733cb 100644 --- a/demo/src/app/components/tooltip/tooltip.routes.ts +++ b/demo/src/app/components/tooltip/tooltip.routes.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdTooltipAutoclose } from './demos/autoclose/tooltip-autoclose'; import { NgbdTooltipBasic } from './demos/basic/tooltip-basic'; import { NgbdTooltipConfig } from './demos/config/tooltip-config'; @@ -13,71 +13,79 @@ import { NgbdTooltipTplcontent } from './demos/tplcontent/tooltip-tplcontent'; import { NgbdTooltipTplwithcontext } from './demos/tplwithcontext/tooltip-tplwithcontext'; import { NgbdTooltipTriggers } from './demos/triggers/tooltip-triggers'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Quick and easy tooltips', type: NgbdTooltipBasic, code: 'tooltip/demos/basic/tooltip-basic.ts', markup: 'tooltip/demos/basic/tooltip-basic.html', }, - tplcontent: { + { + fragment: 'tplcontent', title: 'HTML and bindings in tooltips', type: NgbdTooltipTplcontent, code: 'tooltip/demos/tplcontent/tooltip-tplcontent.ts', markup: 'tooltip/demos/tplcontent/tooltip-tplcontent.html', }, - triggers: { + { + fragment: 'triggers', title: 'Custom and manual triggers', type: NgbdTooltipTriggers, code: 'tooltip/demos/triggers/tooltip-triggers.ts', markup: 'tooltip/demos/triggers/tooltip-triggers.html', }, - autoclose: { + { + fragment: 'autoclose', title: 'Automatic closing with keyboard and mouse', type: NgbdTooltipAutoclose, code: 'tooltip/demos/autoclose/tooltip-autoclose.ts', markup: 'tooltip/demos/autoclose/tooltip-autoclose.html', }, - tplwithcontext: { + { + fragment: 'tplwithcontext', title: 'Context and manual triggers', type: NgbdTooltipTplwithcontext, code: 'tooltip/demos/tplwithcontext/tooltip-tplwithcontext.ts', markup: 'tooltip/demos/tplwithcontext/tooltip-tplwithcontext.html', }, - target: { + { + fragment: 'target', title: 'Custom target', type: NgbdTooltipTarget, code: 'tooltip/demos/custom-target/tooltip-target.ts', markup: 'tooltip/demos/custom-target/tooltip-target.html', }, - delay: { + { + fragment: 'delay', title: 'Open and close delays', type: NgbdTooltipDelay, code: 'tooltip/demos/delay/tooltip-delay.ts', markup: 'tooltip/demos/delay/tooltip-delay.html', }, - container: { + { + fragment: 'container', title: 'Append tooltip in the body', type: NgbdTooltipContainer, code: 'tooltip/demos/container/tooltip-container.ts', markup: 'tooltip/demos/container/tooltip-container.html', }, - customclass: { + { + fragment: 'customclass', title: 'Tooltip with custom class', type: NgbdTooltipCustomclass, code: 'tooltip/demos/customclass/tooltip-customclass.ts', markup: 'tooltip/demos/customclass/tooltip-customclass.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of tooltips', type: NgbdTooltipConfig, code: 'tooltip/demos/config/tooltip-config.ts', markup: 'tooltip/demos/config/tooltip-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -88,15 +96,8 @@ export const ROUTES: Routes = [ name: 'Tooltip', bootstrap: 'https://getbootstrap.com/docs/%version%/components/tooltips/', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('tooltip', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/components/typeahead/typeahead.routes.ts b/demo/src/app/components/typeahead/typeahead.routes.ts index 55ff95f2ce..f244d279ee 100644 --- a/demo/src/app/components/typeahead/typeahead.routes.ts +++ b/demo/src/app/components/typeahead/typeahead.routes.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { ComponentWrapper } from '../../shared/component-wrapper/component-wrapper.component'; import { NgbdApiPage } from '../../shared/api-page/api-page.component'; -import { NgbdExamplesPage } from '../../shared/examples-page/examples.component'; +import { DemoListComponent } from '../../shared/examples-page/demo-list.component'; import { NgbdTypeaheadBasic } from './demos/basic/typeahead-basic'; import { NgbdTypeaheadConfig } from './demos/config/typeahead-config'; import { NgbdTypeaheadFocus } from './demos/focus/typeahead-focus'; @@ -11,59 +11,65 @@ import { NgbdTypeaheadSelectOnExact } from './demos/select-on-exact/typeahead-se import { NgbdTypeaheadTemplate } from './demos/template/typeahead-template'; import { NgbdTypeaheadPreventManualEntry } from './demos/prevent-manual-entry/typeahead-prevent-manual-entry'; import { Routes } from '@angular/router'; -import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core'; -import { NgbdDemoListService } from '../../services/demo-list.service'; -const DEMOS = { - basic: { +const DEMOS = [ + { + fragment: 'basic', title: 'Simple Typeahead', type: NgbdTypeaheadBasic, code: 'typeahead/demos/basic/typeahead-basic.ts', markup: 'typeahead/demos/basic/typeahead-basic.html', }, - focus: { + { + fragment: 'focus', title: 'Open on focus', type: NgbdTypeaheadFocus, code: 'typeahead/demos/focus/typeahead-focus.ts', markup: 'typeahead/demos/focus/typeahead-focus.html', }, - format: { + { + fragment: 'format', title: 'Formatted results', type: NgbdTypeaheadFormat, code: 'typeahead/demos/format/typeahead-format.ts', markup: 'typeahead/demos/format/typeahead-format.html', }, - 'select-on-exact': { + { + fragment: 'select-on-exact', title: 'Select on exact', type: NgbdTypeaheadSelectOnExact, code: 'typeahead/demos/select-on-exact/typeahead-select-on-exact.ts', markup: 'typeahead/demos/select-on-exact/typeahead-select-on-exact.html', }, - http: { + { + fragment: 'http', title: 'Wikipedia search', type: NgbdTypeaheadHttp, code: 'typeahead/demos/http/typeahead-http.ts', markup: 'typeahead/demos/http/typeahead-http.html', }, - template: { + { + fragment: 'template', title: 'Template for results', type: NgbdTypeaheadTemplate, code: 'typeahead/demos/template/typeahead-template.ts', markup: 'typeahead/demos/template/typeahead-template.html', }, - 'prevent-manual-entry': { + { + fragment: 'prevent-manual-entry', title: 'Prevent manual entry', type: NgbdTypeaheadPreventManualEntry, code: 'typeahead/demos/prevent-manual-entry/typeahead-prevent-manual-entry.ts', markup: 'typeahead/demos/prevent-manual-entry/typeahead-prevent-manual-entry.html', }, - config: { + { + fragment: 'config', title: 'Global configuration of typeaheads', type: NgbdTypeaheadConfig, code: 'typeahead/demos/config/typeahead-config.ts', markup: 'typeahead/demos/config/typeahead-config.html', }, -}; +]; export const ROUTES: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'examples' }, @@ -73,15 +79,8 @@ export const ROUTES: Routes = [ data: { name: 'Typeahead', }, - providers: [ - { - provide: ENVIRONMENT_INITIALIZER, - multi: true, - useValue: () => inject(NgbdDemoListService).register('typeahead', DEMOS), - }, - ], children: [ - { path: 'examples', component: NgbdExamplesPage }, + { path: 'examples', component: DemoListComponent, data: { demos: DEMOS } }, { path: 'api', component: NgbdApiPage }, ], }, diff --git a/demo/src/app/pages/animations/animations.page.ts b/demo/src/app/pages/animations/animations.page.ts index e62033f91f..7cda2bfbdb 100644 --- a/demo/src/app/pages/animations/animations.page.ts +++ b/demo/src/app/pages/animations/animations.page.ts @@ -3,12 +3,12 @@ import { Snippet } from '../../services/snippet'; import { LIB_VERSIONS } from '../../tokens'; import { CodeComponent } from '../../shared/code.component'; import { RouterLink } from '@angular/router'; -import { NgbdPageHeaderComponent } from '../../shared/page-wrapper/page-header.component'; +import { PageHeaderComponent } from '../../shared/page-header.component'; import { NgbdPageWrapper } from '../../shared/page-wrapper/page-wrapper.component'; @Component({ standalone: true, - imports: [CodeComponent, RouterLink, NgbdPageHeaderComponent, NgbdPageWrapper], + imports: [CodeComponent, RouterLink, PageHeaderComponent, NgbdPageWrapper], templateUrl: './animations.page.html', }) export class AnimationsPage { diff --git a/demo/src/app/pages/getting-started/getting-started.page.ts b/demo/src/app/pages/getting-started/getting-started.page.ts index 791c9f877a..429e352f4d 100644 --- a/demo/src/app/pages/getting-started/getting-started.page.ts +++ b/demo/src/app/pages/getting-started/getting-started.page.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { Snippet } from '../../services/snippet'; import { LIB_VERSIONS } from '../../tokens'; -import { NgbdPageHeaderComponent } from '../../shared/page-wrapper/page-header.component'; +import { PageHeaderComponent } from '../../shared/page-header.component'; import { CodeComponent } from '../../shared/code.component'; import { NgbdPageWrapper } from '../../shared/page-wrapper/page-wrapper.component'; import { NgbAlertModule, NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; @@ -9,7 +9,7 @@ import { NgIf } from '@angular/common'; @Component({ standalone: true, - imports: [NgbdPageHeaderComponent, CodeComponent, NgbCollapseModule, NgbAlertModule, NgIf, NgbdPageWrapper], + imports: [PageHeaderComponent, CodeComponent, NgbCollapseModule, NgbAlertModule, NgIf, NgbdPageWrapper], templateUrl: './getting-started.page.html', changeDetection: ChangeDetectionStrategy.OnPush, }) diff --git a/demo/src/app/pages/positioning/positioning.page.ts b/demo/src/app/pages/positioning/positioning.page.ts index 59d3a421c1..a14f58963a 100644 --- a/demo/src/app/pages/positioning/positioning.page.ts +++ b/demo/src/app/pages/positioning/positioning.page.ts @@ -4,12 +4,12 @@ import { CodeComponent } from '../../shared/code.component'; import { NgbdPageWrapper } from '../../shared/page-wrapper/page-wrapper.component'; import { RouterLink } from '@angular/router'; import { NgbdApiDocsBadge } from '../../shared/api-docs'; -import { NgbdPageHeaderComponent } from '../../shared/page-wrapper/page-header.component'; +import { PageHeaderComponent } from '../../shared/page-header.component'; import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; @Component({ standalone: true, - imports: [CodeComponent, NgbdPageWrapper, RouterLink, NgbdApiDocsBadge, NgbdPageHeaderComponent, NgbTooltipModule], + imports: [CodeComponent, NgbdPageWrapper, RouterLink, NgbdApiDocsBadge, PageHeaderComponent, NgbTooltipModule], templateUrl: './positioning.page.html', }) export class PositioningPage { diff --git a/demo/src/app/services/demo-list.service.ts b/demo/src/app/services/demo-list.service.ts deleted file mode 100644 index 1add031757..0000000000 --- a/demo/src/app/services/demo-list.service.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Injectable } from '@angular/core'; - -export interface NgbdDemoConfig { - id?: string; - title: string; - code?: string; - markup?: string; - type: any; - files?: Array<{ [name: string]: string }>; - showCode?: boolean; -} - -export interface NgbdDemoListConfig { - [demo: string]: NgbdDemoConfig; -} - -export interface NgbdDemoOverviewConfig { - [anchor: string]: string; -} - -@Injectable({ providedIn: 'root' }) -export class NgbdDemoListService { - private _demos: { [widget: string]: NgbdDemoListConfig } = {}; - - private _overviews: { [widget: string]: NgbdDemoOverviewConfig } = {}; - - register(widget: string, list: NgbdDemoListConfig, overview?: NgbdDemoOverviewConfig) { - this._demos[widget] = list; - if (overview) { - this._overviews[widget] = overview; - } - } - - getDemos(widget: string) { - return this._demos[widget]; - } - - getOverviewSections(widget: string) { - const overview = this._overviews[widget]; - const sections = {}; - if (overview) { - Object.keys(overview).forEach((fragment) => { - sections[fragment] = { fragment, title: overview[fragment] }; - }); - } - return sections; - } -} diff --git a/demo/src/app/shared/component-wrapper/component-wrapper.component.ts b/demo/src/app/shared/component-wrapper/component-wrapper.component.ts index bed1564145..8b85a52d81 100644 --- a/demo/src/app/shared/component-wrapper/component-wrapper.component.ts +++ b/demo/src/app/shared/component-wrapper/component-wrapper.component.ts @@ -1,8 +1,8 @@ import { Component, inject, NgZone } from '@angular/core'; -import { ActivatedRoute, RouterLink, RouterOutlet } from '@angular/router'; +import { ActivatedRoute, NavigationEnd, Router, RouterLink, RouterOutlet } from '@angular/router'; import { NgbdApiPage } from '../api-page/api-page.component'; -import { NgbdExamplesPage } from '../examples-page/examples.component'; +import { DemoListComponent } from '../examples-page/demo-list.component'; import { LIB_VERSIONS } from '../../tokens'; import { SideNavComponent } from '../side-nav/side-nav.component'; import { AsyncPipe, NgComponentOutlet, NgFor, NgIf, TitleCasePipe } from '@angular/common'; @@ -13,6 +13,8 @@ import { NgbScrollSpyItem, NgbScrollSpyService, } from '@ng-bootstrap/ng-bootstrap'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { filter, map } from 'rxjs/operators'; export type TableOfContents = { fragment: string; title: string }[]; @@ -39,7 +41,7 @@ export class ComponentWrapper { private route = inject(ActivatedRoute); componentName = this.route.snapshot.data.name; - activeTab = this.route.firstChild!.routeConfig?.path!; + activeTab: string; headerComponentType = this.route.snapshot.data.header; bootstrapUrl = this.route.snapshot.data.bootstrap?.replace('%version%', inject(LIB_VERSIONS).bootstrap); childrenRouteConfig = this.route.routeConfig!.children!; @@ -52,6 +54,16 @@ export class ComponentWrapper { tableOfContents: TableOfContents = []; constructor() { + inject(Router) + .events.pipe( + takeUntilDestroyed(), + filter((event) => event instanceof NavigationEnd), + map(() => this.route.snapshot.firstChild!.url[0].path!), + ) + .subscribe((url) => { + this.activeTab = url; + }); + // information extracted from https://getbootstrap.com/docs/4.1/layout/overview/ // TODO: we should implements our own mediamatcher, according to bootstrap layout. const zone = inject(NgZone); @@ -66,7 +78,7 @@ export class ComponentWrapper { largeScreenQL.addListener((event) => zone.run(() => (this.isLargeScreenOrLess = event.matches))); } - onActivate(component: NgbdExamplesPage | NgbdApiPage | any) { + onActivate(component: DemoListComponent | NgbdApiPage | any) { setTimeout(() => { const getLinks = (typeCollection: string[]) => { return typeCollection.map((item) => ({ @@ -75,13 +87,11 @@ export class ComponentWrapper { })); }; this.tableOfContents = []; - if (component instanceof NgbdExamplesPage) { - this.tableOfContents = component.demos.map((demo) => { - return { - fragment: demo.id, - title: demo.title, - }; - }); + if (component instanceof DemoListComponent) { + this.tableOfContents = component.demos.map((demo) => ({ + fragment: demo.fragment, + title: demo.title, + })); } else if (component instanceof NgbdApiPage) { let toc = getLinks(component.components); @@ -98,7 +108,10 @@ export class ComponentWrapper { this.tableOfContents = toc; } /* Overview */ else { // TODO: maybe we should also have an abstract class to test instanceof - this.tableOfContents = Object.values(component.sections).map((section) => section) as TableOfContents; + this.tableOfContents = Object.keys(component.overview).map((key: any) => ({ + fragment: key, + title: component.overview[key], + })); } this.scrollSpy.start({ diff --git a/demo/src/app/shared/examples-page/demo-list.component.ts b/demo/src/app/shared/examples-page/demo-list.component.ts new file mode 100644 index 0000000000..46f10856b1 --- /dev/null +++ b/demo/src/app/shared/examples-page/demo-list.component.ts @@ -0,0 +1,28 @@ +import { Component, inject, Input } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { NgbdWidgetDemoComponent } from './demo.component'; +import { NgComponentOutlet, NgFor } from '@angular/common'; + +@Component({ + standalone: true, + imports: [NgbdWidgetDemoComponent, NgComponentOutlet, NgFor], + template: ` + + + + `, +}) +export class DemoListComponent { + componentName = inject(ActivatedRoute).parent!.snapshot.data.name; + @Input() demos: any; +} diff --git a/demo/src/app/shared/examples-page/demo.component.html b/demo/src/app/shared/examples-page/demo.component.html index 3f655c9990..46360c2292 100644 --- a/demo/src/app/shared/examples-page/demo.component.html +++ b/demo/src/app/shared/examples-page/demo.component.html @@ -1,6 +1,6 @@
    -

    - +

    + {{ demoTitle }} @@ -23,7 +23,7 @@

    (click)="trackStackBlitzClick()" class="stackblitz btn-sm btn btn-outline-secondary" target="_blank" - href="stackblitzes/{{ component }}/{{ id }}/stackblitz.html" + href="stackblitzes/{{ component }}/{{ fragment }}/stackblitz.html" title="Edit in StackBlitz" > StackBlitz icon @@ -50,15 +50,15 @@

    -
  • +
  • - {{ component }}-{{ id }}.html + {{ component }}-{{ fragment }}.html
  • -
  • +
  • - {{ component }}-{{ id }}.ts + {{ component }}-{{ fragment }}.ts
  • diff --git a/demo/src/app/shared/examples-page/demo.component.ts b/demo/src/app/shared/examples-page/demo.component.ts index 7c15416681..9ea308ef80 100644 --- a/demo/src/app/shared/examples-page/demo.component.ts +++ b/demo/src/app/shared/examples-page/demo.component.ts @@ -25,12 +25,12 @@ const TYPES: { [name: string]: string } = { export class NgbdWidgetDemoComponent { @Input() demoTitle: string; @Input() component: string; - @Input() id: string; + @Input() fragment: string; @Input() code: string; @Input() markup: string; @Input() files: { name: string; source: string }[]; @Input() showCode = false; - @Input() showStackblitz; + @Input() showStackblitz: boolean; codeService = inject(NgbdDemoCodeService); @@ -56,11 +56,11 @@ export class NgbdWidgetDemoComponent { } trackStackBlitzClick() { - this._analytics.trackEvent('StackBlitz View', this.component + ' ' + this.id); + this._analytics.trackEvent('StackBlitz View', this.component + ' ' + this.fragment); } trackShowCodeClick() { if (this.showCode) { - this._analytics.trackEvent('Show Code View', this.component + ' ' + this.id); + this._analytics.trackEvent('Show Code View', this.component + ' ' + this.fragment); } } } diff --git a/demo/src/app/shared/examples-page/examples.component.ts b/demo/src/app/shared/examples-page/examples.component.ts deleted file mode 100644 index 41e736a217..0000000000 --- a/demo/src/app/shared/examples-page/examples.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; - -import { NgbdDemoListService } from '../../services/demo-list.service'; -import { NgbdWidgetDemoComponent } from './demo.component'; -import { NgComponentOutlet, NgFor } from '@angular/common'; - -@Component({ - standalone: true, - imports: [NgbdWidgetDemoComponent, NgComponentOutlet, NgFor], - template: ` - - - - `, -}) -export class NgbdExamplesPage { - component: string; - demos: any = []; - - constructor(route: ActivatedRoute, demoList: NgbdDemoListService) { - // We go up to parent route defining /components/:widget to read the widget name - // This route is declared in root app.routing.ts. - const componentName = (this.component = route.parent!.parent!.snapshot.url[1].path); - if (componentName) { - const demos = demoList.getDemos(componentName); - if (demos) { - this.demos = Object.keys(demos).map((id) => { - return { id, ...demos[id] }; - }); - } - } - } -} diff --git a/demo/src/app/shared/overview/overview-section.component.ts b/demo/src/app/shared/overview/overview-section.component.ts deleted file mode 100644 index fd61631f29..0000000000 --- a/demo/src/app/shared/overview/overview-section.component.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; - -import { NgbdOverviewSection } from './overview'; -import { RouterLink } from '@angular/router'; - -@Component({ - selector: 'ngbd-overview-section', - standalone: true, - imports: [RouterLink], - changeDetection: ChangeDetectionStrategy.OnPush, - host: { - class: 'd-block', - }, - template: ` -

    - - - - {{ section.title }} -

    - - - `, -}) -export class NgbdOverviewSectionComponent { - @Input() section: NgbdOverviewSection; -} diff --git a/demo/src/app/shared/overview/overview.directive.ts b/demo/src/app/shared/overview/overview.directive.ts deleted file mode 100644 index e305d18104..0000000000 --- a/demo/src/app/shared/overview/overview.directive.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Directive } from '@angular/core'; - -@Directive({ - standalone: true, - selector: '[ngbdOverview]', -}) -export class NgbdOverviewDirective {} diff --git a/demo/src/app/shared/overview/overview.ts b/demo/src/app/shared/overview/overview.ts deleted file mode 100644 index 4fce3a9580..0000000000 --- a/demo/src/app/shared/overview/overview.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface NgbdOverviewSection { - title: string | false; - fragment: string; -} - -export interface NgbdOverview { - [fragment: string]: NgbdOverviewSection; -} diff --git a/demo/src/app/shared/page-wrapper/page-header.component.ts b/demo/src/app/shared/page-header.component.ts similarity index 81% rename from demo/src/app/shared/page-wrapper/page-header.component.ts rename to demo/src/app/shared/page-header.component.ts index b88dc9ce63..ea8f234136 100644 --- a/demo/src/app/shared/page-wrapper/page-header.component.ts +++ b/demo/src/app/shared/page-header.component.ts @@ -1,6 +1,5 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { RouterLink } from '@angular/router'; -import { NgbdOverviewSection } from '../overview/overview'; @Component({ selector: 'ngbd-page-header', @@ -17,9 +16,10 @@ import { NgbdOverviewSection } from '../overview/overview'; {{ title }}

    + `, }) -export class NgbdPageHeaderComponent implements NgbdOverviewSection { - @Input() title: string; +export class PageHeaderComponent { @Input() fragment: string; + @Input() title: string; } diff --git a/demo/src/app/shared/page-wrapper/page-wrapper.component.ts b/demo/src/app/shared/page-wrapper/page-wrapper.component.ts index 301cd9843e..e7b47bb496 100644 --- a/demo/src/app/shared/page-wrapper/page-wrapper.component.ts +++ b/demo/src/app/shared/page-wrapper/page-wrapper.component.ts @@ -1,5 +1,5 @@ import { AfterViewInit, Component, ContentChildren, inject, Input, NgZone, QueryList } from '@angular/core'; -import { NgbdPageHeaderComponent } from './page-header.component'; +import { PageHeaderComponent } from '../page-header.component'; import { TableOfContents } from '../component-wrapper/component-wrapper.component'; import { NgbCollapseModule, @@ -20,7 +20,7 @@ import { SideNavComponent } from '../side-nav/side-nav.component'; export class NgbdPageWrapper implements AfterViewInit { @Input() pageTitle: string; - @ContentChildren(NgbdPageHeaderComponent) private _tableOfContents: QueryList; + @ContentChildren(PageHeaderComponent) private _tableOfContents: QueryList; sidebarCollapsed = true; isLargeScreenOrLess: boolean; diff --git a/demo/src/main.ts b/demo/src/main.ts index 0d37273b72..ecdafe9f7c 100644 --- a/demo/src/main.ts +++ b/demo/src/main.ts @@ -5,6 +5,7 @@ import { AppComponent } from './app/app.component'; import { PreloadAllModules, provideRouter, + withComponentInputBinding, withHashLocation, withInMemoryScrolling, withPreloading, @@ -20,6 +21,7 @@ bootstrapApplication(AppComponent, { ROUTES, withPreloading(PreloadAllModules), withHashLocation(), + withComponentInputBinding(), withInMemoryScrolling({ anchorScrolling: 'enabled', scrollPositionRestoration: 'enabled',