diff --git a/.devcontainer/scripts/postStartCommand.sh b/.devcontainer/scripts/postStartCommand.sh old mode 100755 new mode 100644 diff --git a/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll-list-item.component.ts b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll-list-item.component.ts new file mode 100644 index 00000000..f5daf512 --- /dev/null +++ b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll-list-item.component.ts @@ -0,0 +1,95 @@ +import { AsyncPipe } from '@angular/common'; +import { ChangeDetectionStrategy, Component, DestroyRef, EventEmitter, inject, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { + IsActiveMatchOptions, + NavigationEnd, + Router, + Event as RouterEvent, + RouterLink, + RouterLinkActive, + RouterLinkWithHref, + Scroll, +} from '@angular/router'; +import { AsyncSubject, filter, switchMap, tap } from 'rxjs'; +import { ItNavscrollListItemsComponent } from './navscroll-list-items.component'; +import { NavscrollItem } from './navscroll.model'; +import { NavscrollStore } from './navscroll.store'; + +const ROUTER_LINK_ACTIVE_OPTIONS: IsActiveMatchOptions = { + fragment: 'exact', + paths: 'exact', + queryParams: 'exact', + matrixParams: 'exact', +}; + +@Component({ + selector: 'it-navscroll-list-item', + standalone: true, + imports: [RouterLink, RouterLinkActive, RouterLinkWithHref, ItNavscrollListItemsComponent, AsyncPipe], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + {{ item?.title }} + `, +}) +export class ItNavscrollListItemComponent implements OnInit { + @Input() item!: NavscrollItem; + + @Output() readonly checkActive = new EventEmitter(); + + @ViewChild('rtl') + readonly rtl: any; + + readonly routerLinkActiveOptions = ROUTER_LINK_ACTIVE_OPTIONS; + + readonly #initIsActive = new AsyncSubject(); + + readonly active = this.#initIsActive.asObservable().pipe(switchMap(item => this.#store.isActive$(item))); + + readonly #router = inject(Router); + + readonly #store = inject(NavscrollStore); + + readonly #destroyRef = inject(DestroyRef); + + ngOnInit() { + this.#initIsActiveSub(); + this.#router.events + .pipe( + takeUntilDestroyed(this.#destroyRef), + filter((event: RouterEvent) => { + const isNavigationEndEvent = event instanceof NavigationEnd; + const isScrollEvent = event instanceof Scroll && (event as Scroll).routerEvent instanceof NavigationEnd; + return isNavigationEndEvent || isScrollEvent; + }), + tap(() => { + if (this.rtl?.isActive) { + this.#store.setActive(this.item); + } + }) + ) + .subscribe(); + } + + clickHandler(event: Event) { + event.preventDefault(); + this.#store.selectMenuItem(); + this.#router.navigate([], { fragment: this.item.href }); + } + + #initIsActiveSub() { + this.#initIsActive.next(this.item); + this.#initIsActive.complete(); + } +} diff --git a/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll-list-items.component.ts b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll-list-items.component.ts new file mode 100644 index 00000000..076cb753 --- /dev/null +++ b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll-list-items.component.ts @@ -0,0 +1,27 @@ +import { JsonPipe, NgTemplateOutlet } from '@angular/common'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { RouterLink, RouterLinkActive, RouterLinkWithHref } from '@angular/router'; +import { ItNavscrollListItemComponent } from './navscroll-list-item.component'; +import { NavscrollItems } from './navscroll.model'; + +@Component({ + selector: 'it-navscroll-list-items', + standalone: true, + imports: [NgTemplateOutlet, RouterLink, RouterLinkActive, RouterLinkWithHref, JsonPipe, ItNavscrollListItemComponent], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + `, +}) +export class ItNavscrollListItemsComponent { + @Input() items!: NavscrollItems; +} diff --git a/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.component.html b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.component.html new file mode 100644 index 00000000..3a604667 --- /dev/null +++ b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.component.html @@ -0,0 +1,101 @@ +
+
+
+
+ +
+
+
+ + +
+
+
+ + + @for (item of items; track item.href) { + + } + + + + @switch (level) { + @case (1) { +

{{ item.title }}

+ } + @case (2) { +

{{ item.title }}

+ } + @case (3) { +

{{ item.title }}

+ } + @case (4) { +
{{ item.title }}
+ } + @default { +
{{ item.title }}
+ } + } +

{{ item.text }}

+ @for (item of item.childs; track item.href) { + + } +
diff --git a/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.component.scss b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.component.scss new file mode 100644 index 00000000..7be7002f --- /dev/null +++ b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.component.scss @@ -0,0 +1,9 @@ +.it-navscroll-sticky { + // data-bs-toggle="sticky" + position: sticky; + top: 0; +} + +.it-navscroll-sticky-mobile { + z-index: 1020; +} diff --git a/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.component.ts b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.component.ts new file mode 100644 index 00000000..41a1016c --- /dev/null +++ b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.component.ts @@ -0,0 +1,143 @@ +import { AsyncPipe, NgClass, NgTemplateOutlet, ViewportScroller } from '@angular/common'; +import { + ChangeDetectionStrategy, + Component, + DestroyRef, + ElementRef, + HostListener, + inject, + Input, + OnInit, + TemplateRef, + ViewChild, +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { RouterLink, RouterLinkActive, RouterLinkWithHref } from '@angular/router'; +import { delay, filter, map, tap, withLatestFrom } from 'rxjs'; +import { ItNavscrollListItemsComponent } from './navscroll-list-items.component'; +import { NavscrollItem } from './navscroll.model'; +import { NavscrollStore } from './navscroll.store'; + +/** + * Navscroll + * @description Show a list of links to anchor of the document. + */ +@Component({ + selector: 'it-navscroll', + standalone: true, + imports: [ + ItNavscrollListItemsComponent, + AsyncPipe, + NgTemplateOutlet, + RouterLink, + RouterLinkActive, + RouterLinkWithHref, + AsyncPipe, + NgClass, + ], + templateUrl: './navscroll.component.html', + styleUrl: './navscroll.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [NavscrollStore], +}) +export class ItNavscrollComponent implements OnInit { + /** + * Header of the Navscroll + */ + @Input() readonly header = ''; + /** + * A list of links + */ + @Input() readonly items!: Array; + /** + * Border position + * @default left + */ + @Input() readonly borderPosition: 'left' | 'right' = 'left'; + /** + * Alignment + * @default top + */ + @Input() readonly alignment: 'top' | 'bottom' = 'top'; + + /** + * Theme + * @default light + */ + @Input() readonly theme: 'light' | 'dark' = 'light'; + + /** + * Custom template for the content section + */ + @Input() + pageSectionsTemplate?: TemplateRef; + + @HostListener('window:scroll', ['$event']) // for window scroll events + onScroll() { + const sectionContainer = this.#elementRef.nativeElement.querySelector('.it-page-sections-container'); + this.#store.updateProgressBar(sectionContainer); + } + + @HostListener('window:resize', ['$event']) + onResize() { + this.#setMobile(); + } + + @ViewChild('toggleButtonRef') + readonly toggleButtonRef!: ElementRef; + + readonly #store = inject(NavscrollStore); + + readonly #scroller = inject(ViewportScroller); + + readonly #destroyRef = inject(DestroyRef); + + readonly #elementRef = inject(ElementRef); + + readonly selectedTitle = this.#store.selected.pipe(map(selected => selected?.title ?? '')); + + readonly progressBarValue = this.#store.progressBar; + + readonly isMobile = this.#store.isMobile; + + constructor() { + this.#store.menuItemSelected + .pipe( + takeUntilDestroyed(), + withLatestFrom(this.isMobile), + tap(v => { + const isMobile = v[1]; + if (isMobile) { + this.toggleButtonRef.nativeElement.click(); + } + }) + ) + .subscribe(); + } + + ngOnInit(): void { + this.#initViewScrollerSubscription(); + this.#store.init(this.items); + this.#setMobile(); + } + + #initViewScrollerSubscription() { + this.#store.selected + .pipe( + takeUntilDestroyed(this.#destroyRef), + filter(selected => Boolean(selected)), + map(v => v as NavscrollItem), + delay(0), //WA + tap({ + next: ({ href }) => { + this.#scroller.scrollToAnchor(href); + }, + }) + ) + .subscribe(); + } + + #setMobile() { + this.#store.setMobile(window); + } +} diff --git a/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.model.ts b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.model.ts new file mode 100644 index 00000000..4b7b4b6f --- /dev/null +++ b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.model.ts @@ -0,0 +1,12 @@ +export interface NavscrollItem { + title: string; + text: string; + href: string; + childs: NavscrollItems; +} + +export type NavscrollItems = Array; + +export interface NavscrollItemActive { + active: boolean; +} diff --git a/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.store.ts b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.store.ts new file mode 100644 index 00000000..102847af --- /dev/null +++ b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.store.ts @@ -0,0 +1,93 @@ +import { BehaviorSubject, distinctUntilChanged, map, Subject } from 'rxjs'; +import { NavscrollItem } from './navscroll.model'; +import { flattenNavscrollItems, search } from './navscroll.utils'; + +interface NavscrollState { + items: Set; + active: Array; + selected?: NavscrollItem; + progressBar: number; + isMobile: boolean; +} + +export class NavscrollStore { + readonly #state = new BehaviorSubject({ + items: new Set(), + active: [], + selected: undefined, + progressBar: 0, + isMobile: false, + }); + + readonly #state$ = this.#state.asObservable(); + + readonly selected = this.#state$.pipe( + map(({ selected }) => selected), + distinctUntilChanged() + ); + + readonly progressBar = this.#state$.pipe( + map(({ progressBar }) => progressBar), + distinctUntilChanged() + ); + + readonly isMobile = this.#state$.pipe( + map(({ isMobile }) => isMobile), + distinctUntilChanged() + ); + + readonly #menuItemSelected = new Subject(); + + readonly menuItemSelected = this.#menuItemSelected.asObservable(); + + init(navscrollItems: Array) { + const flattenItems = flattenNavscrollItems(navscrollItems); + //the first item is selected by default + const selected = ((flattenItems && flattenItems.length && flattenItems[0]) as NavscrollItem) ?? undefined; + + const state = { + items: new Set(flattenItems), + active: selected ? [selected] : [], + selected: selected, + progressBar: 0, + isMobile: false, + }; + + this.#state.next(state); + } + + setActive(item: NavscrollItem) { + const { items } = this.#state.value; + + const active = search(items, item); + const state = this.#state.value; + this.#state.next({ ...state, items, selected: item, active }); + } + + isActive$(item: NavscrollItem) { + return this.#state.asObservable().pipe(map(state => state.active.includes(item))); + } + + updateProgressBar(container: HTMLElement) { + if (!container) { + return; + } + const offset = Math.abs(container.getBoundingClientRect().top); + const height = container.getBoundingClientRect().height; + const scrollAmount = (offset / height) * 100; + const scrollValue = Math.min(100, Math.max(0, scrollAmount)); + const state = this.#state.value; + this.#state.next({ ...state, progressBar: scrollValue }); + } + + selectMenuItem() { + this.#menuItemSelected.next(undefined); + } + + setMobile({ innerWidth }: { innerWidth: number }) { + const isLessThan992px = innerWidth < 992; + const isMobile = isLessThan992px; + const state = this.#state.value; + this.#state.next({ ...state, isMobile }); + } +} diff --git a/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.utils.ts b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.utils.ts new file mode 100644 index 00000000..bb4fd13f --- /dev/null +++ b/projects/design-angular-kit/src/lib/components/navigation/navscroll/navscroll.utils.ts @@ -0,0 +1,28 @@ +import { NavscrollItem, NavscrollItems } from './navscroll.model'; + +function searchFn(items: Set, item: NavscrollItem): Array { + //ricerca + const nodes = Array.from(items); + const parent = nodes.find(i => i.childs.includes(item)); + const ancestors = parent?.childs?.length ? searchFn(items, parent) : []; + return [item, ...ancestors]; +} + +function flattenNavscrollItemsFn(items: NavscrollItems): NavscrollItems { + const result: NavscrollItems = []; + + function flatten(items: NavscrollItems): void { + for (const item of items) { + result.push(item); + if (item.childs && item.childs.length > 0) { + flatten(item.childs); + } + } + } + + flatten(items); + return result; +} + +export const search = searchFn; +export const flattenNavscrollItems = flattenNavscrollItemsFn; diff --git a/projects/design-angular-kit/src/lib/design-angular-kit.module.ts b/projects/design-angular-kit/src/lib/design-angular-kit.module.ts index 0b4a697f..da5a5e3b 100644 --- a/projects/design-angular-kit/src/lib/design-angular-kit.module.ts +++ b/projects/design-angular-kit/src/lib/design-angular-kit.module.ts @@ -1,6 +1,4 @@ import { ModuleWithProviders, NgModule } from '@angular/core'; -import { DesignAngularKitConfig } from './interfaces/design-angular-kit-config'; -import { provideDesignAngularKit } from './provide-design-angular-kit'; import { ItAccordionComponent } from './components/core/accordion/accordion.component'; import { ItAlertComponent } from './components/core/alert/alert.component'; import { ItAvatarModule } from './components/core/avatar/avatar.module'; @@ -16,7 +14,6 @@ import { ItDropdownModule } from './components/core/dropdown/dropdown.module'; import { ItForwardDirective } from './components/core/forward/forward.directive'; import { ItLinkComponent } from './components/core/link/link.component'; import { ItListModule } from './components/core/list/list.module'; -import { ItMegamenuComponent } from './components/navigation/megamenu/megamenu.component'; import { ItModalComponent } from './components/core/modal/modal.component'; import { ItNotificationsComponent } from './components/core/notifications/notifications.component'; import { ItPaginationComponent } from './components/core/pagination/pagination.component'; @@ -27,21 +24,25 @@ import { ItSpinnerComponent } from './components/core/spinner/spinner.component' import { ItSteppersModule } from './components/core/steppers/steppers.module'; import { ItTabModule } from './components/core/tab/tab.module'; import { ItTableModule } from './components/core/table/table.module'; +import { ItTimelineModule } from './components/core/timeline/timeline.module'; import { ItTooltipDirective } from './components/core/tooltip/tooltip.directive'; import { ItFormModule } from './components/form/form.module'; import { ItBackButtonComponent } from './components/navigation/back-button/back-button.component'; import { ItBackToTopComponent } from './components/navigation/back-to-top/back-to-top.component'; import { ItBreadcrumbsModule } from './components/navigation/breadcrumbs/breadcrumbs.module'; import { ItHeaderComponent } from './components/navigation/header/header.component'; +import { ItMegamenuComponent } from './components/navigation/megamenu/megamenu.component'; import { ItNavBarModule } from './components/navigation/navbar/navbar.module'; +import { ItNavscrollComponent } from './components/navigation/navscroll/navscroll.component'; import { ItSidebarComponent } from './components/navigation/sidebar/sidebar.component'; import { ItErrorPageComponent } from './components/utils/error-page/error-page.component'; import { ItIconComponent } from './components/utils/icon/icon.component'; import { ItLanguageSwitcherComponent } from './components/utils/language-switcher/language-switcher.component'; +import { DesignAngularKitConfig } from './interfaces/design-angular-kit-config'; import { ItDateAgoPipe } from './pipes/date-ago.pipe'; import { ItDurationPipe } from './pipes/duration.pipe'; import { ItMarkMatchingTextPipe } from './pipes/mark-matching-text.pipe'; -import { ItTimelineModule } from './components/core/timeline/timeline.module'; +import { provideDesignAngularKit } from './provide-design-angular-kit'; /** * Core components @@ -87,6 +88,7 @@ const navigation = [ ItNavBarModule, ItSidebarComponent, ItMegamenuComponent, + ItNavscrollComponent, ]; /** diff --git a/projects/design-angular-kit/src/public_api.ts b/projects/design-angular-kit/src/public_api.ts index 63fbfc95..e5994c59 100644 --- a/projects/design-angular-kit/src/public_api.ts +++ b/projects/design-angular-kit/src/public_api.ts @@ -100,6 +100,9 @@ export * from './lib/components/navigation/navbar/navbar-item/navbar-item.compon export * from './lib/components/navigation/navbar/navbar.module'; export * from './lib/components/navigation/navbar/navbar/navbar.component'; +export * from './lib/components/navigation/navscroll/navscroll.component'; +export * from './lib/components/navigation/navscroll/navscroll.model'; + export * from './lib/components/navigation/sidebar/sidebar.component'; // Utils components diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index ec7d72cb..f2ea5c5c 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,7 +1,8 @@ import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { RouterDispatcherComponent } from './router-dispatcher/router-dispatcher.component'; +import { RouterModule, Routes } from '@angular/router'; import { ItErrorPageComponent } from 'design-angular-kit/components/utils/error-page/error-page.component'; +import { EXAMPLES_ROUTES } from './examples/routes'; +import { RouterDispatcherComponent } from './router-dispatcher/router-dispatcher.component'; const routes: Routes = [ { path: '', redirectTo: 'info', pathMatch: 'full' }, @@ -68,9 +69,11 @@ const routes: Routes = [ { path: 'autocomplete', loadChildren: () => import('src/app/autocomplete/autocomplete.module').then(m => m.AutocompleteModule) }, { path: 'sidebar', loadChildren: () => import('src/app/sidebar/sidebar.module').then(m => m.SidebarModule) }, { path: 'timeline', loadChildren: () => import('src/app/timeline/timeline.module').then(m => m.TimelineModule) }, + { path: 'navscroll', loadChildren: () => import('src/app/navscroll/navscroll.module').then(m => m.NavscrollModule) }, { path: 'transfer', loadChildren: () => import('src/app/transfer/transfer.module').then(m => m.TransferModule) }, ], }, + { path: 'esempi', component: RouterDispatcherComponent, children: EXAMPLES_ROUTES }, { path: 'error/not-found', component: ItErrorPageComponent, data: { errorCode: 404 } }, { path: 'error/forbidden', component: ItErrorPageComponent, data: { errorCode: 403 } }, { path: 'error/server-error', component: ItErrorPageComponent, data: { errorCode: 500 } }, diff --git a/src/app/app.component.html b/src/app/app.component.html index 85f39617..de0d8d15 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -79,8 +79,9 @@

data-focus-mouse="false"> v{{ version }} - Changelog + + + Changelog diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4ea33e56..8ecb71f8 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,19 +1,21 @@ -import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { NgTemplateOutlet } from '@angular/common'; +import { TranslateStore } from '@ngx-translate/core'; +import { DesignAngularKitModule } from 'design-angular-kit/design-angular-kit.module'; +import { HIGHLIGHT_OPTIONS } from 'ngx-highlightjs'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; -import { TableOfContentComponent } from './table-of-content/table-of-content.component'; -import { TableOfContentItemComponent } from './table-of-content-item/table-of-content-item.component'; -import { RouterDispatcherComponent } from './router-dispatcher/router-dispatcher.component'; +import { EXAMPLES_MODULES } from './examples'; import { LinkSortPipe } from './link-sort.pipe'; -import { HIGHLIGHT_OPTIONS } from 'ngx-highlightjs'; -import { TranslateStore } from '@ngx-translate/core'; -import { DesignAngularKitModule } from 'design-angular-kit/design-angular-kit.module'; +import { RouterDispatcherComponent } from './router-dispatcher/router-dispatcher.component'; +import { TableOfContentItemComponent } from './table-of-content-item/table-of-content-item.component'; +import { TableOfContentComponent } from './table-of-content/table-of-content.component'; @NgModule({ declarations: [AppComponent, TableOfContentComponent, TableOfContentItemComponent, RouterDispatcherComponent, LinkSortPipe], - imports: [BrowserModule, AppRoutingModule, DesignAngularKitModule.forRoot()], + imports: [BrowserModule, AppRoutingModule, DesignAngularKitModule.forRoot(), NgTemplateOutlet, ...EXAMPLES_MODULES], providers: [ TranslateStore, { diff --git a/src/app/examples/index.ts b/src/app/examples/index.ts new file mode 100644 index 00000000..2b113dce --- /dev/null +++ b/src/app/examples/index.ts @@ -0,0 +1,3 @@ +import { NavscrollExampleModule } from './navscroll-example/navscroll-example.module'; + +export const EXAMPLES_MODULES = [NavscrollExampleModule]; diff --git a/src/app/examples/navscroll-example/navscroll-example.component.ts b/src/app/examples/navscroll-example/navscroll-example.component.ts new file mode 100644 index 00000000..df0e7568 --- /dev/null +++ b/src/app/examples/navscroll-example/navscroll-example.component.ts @@ -0,0 +1,94 @@ +import { Component } from '@angular/core'; +import { NavscrollItems } from 'projects/design-angular-kit/src/public_api'; + +const template = ` + + +

Documentazione

+`; + +@Component({ + template, +}) +export class NavscrollExampleComponent { + readonly header = 'Default example'; + readonly items = [ + { + title: 'Prima Sezione', + text: 'Testo prima sezione. Proin placerat ipsum massa, ac commodo velit tempor quis. In ante augue, sodales ac rhoncus in, ultricies a neque. Morbi non semper felis, at lacinia nibh. Nam quis elit massa. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam laoreet, diam quis blandit porttitor, leo erat semper sem, vel sagittis dolor quam eu magna. Nunc feugiat pretium tempor. Nam eget augue quis tellus viverra malesuada vel ut quam. Cras vehicula rutrum vehicula. Suspendisse efficitur eget purus vitae convallis. Integer euismod pharetra lorem, non ullamcorper lorem euismod vel. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + href: 'primaSezione', + childs: [ + { + title: 'Sottosezione 1.1', + text: 'Testo sottosezione 1.1. Proin placerat ipsum massa, ac commodo velit tempor quis. In ante augue, sodales ac rhoncus in, ultricies a neque. Morbi non semper felis, at lacinia nibh. Nam quis elit massa. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam laoreet, diam quis blandit porttitor, leo erat semper sem, vel sagittis dolor quam eu magna. Nunc feugiat pretium tempor. Nam eget augue quis tellus viverra malesuada vel ut quam. Cras vehicula rutrum vehicula. Suspendisse efficitur eget purus vitae convallis. Integer euismod pharetra lorem, non ullamcorper lorem euismod vel. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + href: 's11', + childs: [ + { + title: 'Sottosezione 1.1.1', + text: 'Testo sottosezione 1.1.1. Proin placerat ipsum massa, ac commodo velit tempor quis. In ante augue, sodales ac rhoncus in, ultricies a neque. Morbi non semper felis, at lacinia nibh. Nam quis elit massa. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam laoreet, diam quis blandit porttitor, leo erat semper sem, vel sagittis dolor quam eu magna. Nunc feugiat pretium tempor. Nam eget augue quis tellus viverra malesuada vel ut quam. Cras vehicula rutrum vehicula. Suspendisse efficitur eget purus vitae convallis. Integer euismod pharetra lorem, non ullamcorper lorem euismod vel. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + href: 's111', + childs: [ + { + title: 'Sottosezione 1.1.1.1', + text: 'Testo sottosezione 1.1.1.1. Proin placerat ipsum massa, ac commodo velit tempor quis. In ante augue, sodales ac rhoncus in, ultricies a neque. Morbi non semper felis, at lacinia nibh. Nam quis elit massa. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam laoreet, diam quis blandit porttitor, leo erat semper sem, vel sagittis dolor quam eu magna. Nunc feugiat pretium tempor. Nam eget augue quis tellus viverra malesuada vel ut quam. Cras vehicula rutrum vehicula. Suspendisse efficitur eget purus vitae convallis. Integer euismod pharetra lorem, non ullamcorper lorem euismod vel. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + href: 's1111', + childs: [], + }, + ], + }, + { + title: 'Sottosezione 1.1.2', + text: 'Testo sottosezione 1.1.2. Proin placerat ipsum massa, ac commodo velit tempor quis. In ante augue, sodales ac rhoncus in, ultricies a neque. Morbi non semper felis, at lacinia nibh. Nam quis elit massa. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam laoreet, diam quis blandit porttitor, leo erat semper sem, vel sagittis dolor quam eu magna. Nunc feugiat pretium tempor. Nam eget augue quis tellus viverra malesuada vel ut quam. Cras vehicula rutrum vehicula. Suspendisse efficitur eget purus vitae convallis. Integer euismod pharetra lorem, non ullamcorper lorem euismod vel. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + href: 's112', + childs: [], + }, + ], + }, + { + title: 'Sottosezione 1.2', + text: 'Testo sottosezione 1.2. Proin placerat ipsum massa, ac commodo velit tempor quis. In ante augue, sodales ac rhoncus in, ultricies a neque. Morbi non semper felis, at lacinia nibh. Nam quis elit massa. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam laoreet, diam quis blandit porttitor, leo erat semper sem, vel sagittis dolor quam eu magna. Nunc feugiat pretium tempor. Nam eget augue quis tellus viverra malesuada vel ut quam. Cras vehicula rutrum vehicula. Suspendisse efficitur eget purus vitae convallis. Integer euismod pharetra lorem, non ullamcorper lorem euismod vel. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + href: 's12', + childs: [], + }, + { + title: 'Sottosezione 1.3', + text: 'Testo sottosezione 1.3. Proin placerat ipsum massa, ac commodo velit tempor quis. In ante augue, sodales ac rhoncus in, ultricies a neque. Morbi non semper felis, at lacinia nibh. Nam quis elit massa. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam laoreet, diam quis blandit porttitor, leo erat semper sem, vel sagittis dolor quam eu magna. Nunc feugiat pretium tempor. Nam eget augue quis tellus viverra malesuada vel ut quam. Cras vehicula rutrum vehicula. Suspendisse efficitur eget purus vitae convallis. Integer euismod pharetra lorem, non ullamcorper lorem euismod vel. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + href: 's13', + childs: [], + }, + ], + }, + { + title: 'Seconda Sezione', + text: 'Testo seconda sezione. Proin placerat ipsum massa, ac commodo velit tempor quis. In ante augue, sodales ac rhoncus in, ultricies a neque. Morbi non semper felis, at lacinia nibh. Nam quis elit massa. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam laoreet, diam quis blandit porttitor, leo erat semper sem, vel sagittis dolor quam eu magna. Nunc feugiat pretium tempor. Nam eget augue quis tellus viverra malesuada vel ut quam. Cras vehicula rutrum vehicula. Suspendisse efficitur eget purus vitae convallis. Integer euismod pharetra lorem, non ullamcorper lorem euismod vel. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + href: 'secondaSezione', + childs: [ + { + title: 'Sottosezione 2.1', + text: 'Testo sottosezione 2.1. Proin placerat ipsum massa, ac commodo velit tempor quis. In ante augue, sodales ac rhoncus in, ultricies a neque. Morbi non semper felis, at lacinia nibh. Nam quis elit massa. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam laoreet, diam quis blandit porttitor, leo erat semper sem, vel sagittis dolor quam eu magna. Nunc feugiat pretium tempor. Nam eget augue quis tellus viverra malesuada vel ut quam. Cras vehicula rutrum vehicula. Suspendisse efficitur eget purus vitae convallis. Integer euismod pharetra lorem, non ullamcorper lorem euismod vel. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + href: 's21', + childs: [ + { + title: 'Sottosezione 2.1.1', + text: 'Testo sottosezione 2.1.1. Proin placerat ipsum massa, ac commodo velit tempor quis. In ante augue, sodales ac rhoncus in, ultricies a neque. Morbi non semper felis, at lacinia nibh. Nam quis elit massa. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam laoreet, diam quis blandit porttitor, leo erat semper sem, vel sagittis dolor quam eu magna. Nunc feugiat pretium tempor. Nam eget augue quis tellus viverra malesuada vel ut quam. Cras vehicula rutrum vehicula. Suspendisse efficitur eget purus vitae convallis. Integer euismod pharetra lorem, non ullamcorper lorem euismod vel. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + href: 's211', + childs: [], + }, + ], + }, + { + title: 'Sottosezione 2.2', + text: 'Testo sottosezione 2.2. Proin placerat ipsum massa, ac commodo velit tempor quis. In ante augue, sodales ac rhoncus in, ultricies a neque. Morbi non semper felis, at lacinia nibh. Nam quis elit massa. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aliquam laoreet, diam quis blandit porttitor, leo erat semper sem, vel sagittis dolor quam eu magna. Nunc feugiat pretium tempor. Nam eget augue quis tellus viverra malesuada vel ut quam. Cras vehicula rutrum vehicula. Suspendisse efficitur eget purus vitae convallis. Integer euismod pharetra lorem, non ullamcorper lorem euismod vel. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', + href: 's22', + childs: [], + }, + ], + }, + ] satisfies NavscrollItems; +} diff --git a/src/app/examples/navscroll-example/navscroll-example.module.ts b/src/app/examples/navscroll-example/navscroll-example.module.ts new file mode 100644 index 00000000..1a0e366c --- /dev/null +++ b/src/app/examples/navscroll-example/navscroll-example.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { DesignAngularKitModule } from 'projects/design-angular-kit/src/public_api'; +import { NavscrollExampleComponent } from './navscroll-example.component'; + +@NgModule({ + declarations: [NavscrollExampleComponent], + exports: [NavscrollExampleComponent], + imports: [DesignAngularKitModule, RouterModule], +}) +export class NavscrollExampleModule {} diff --git a/src/app/examples/routes.ts b/src/app/examples/routes.ts new file mode 100644 index 00000000..e2bc08b4 --- /dev/null +++ b/src/app/examples/routes.ts @@ -0,0 +1,4 @@ +import { Routes } from '@angular/router'; +import { NavscrollExampleComponent } from './navscroll-example/navscroll-example.component'; + +export const EXAMPLES_ROUTES = [{ path: 'navscroll', component: NavscrollExampleComponent }] satisfies Routes; diff --git a/src/app/navscroll/navscroll-custom-template-example/navscroll-custom-template-example.component.html b/src/app/navscroll/navscroll-custom-template-example/navscroll-custom-template-example.component.html new file mode 100644 index 00000000..1db105d4 --- /dev/null +++ b/src/app/navscroll/navscroll-custom-template-example/navscroll-custom-template-example.component.html @@ -0,0 +1,6 @@ + +

This is a custom template

+

All the paragraphs will be displayed here

+
+ + diff --git a/src/app/navscroll/navscroll-custom-template-example/navscroll-custom-template-example.component.ts b/src/app/navscroll/navscroll-custom-template-example/navscroll-custom-template-example.component.ts new file mode 100644 index 00000000..9acf7b8e --- /dev/null +++ b/src/app/navscroll/navscroll-custom-template-example/navscroll-custom-template-example.component.ts @@ -0,0 +1,76 @@ +import { Component } from '@angular/core'; +import { NavscrollItems } from 'projects/design-angular-kit/src/public_api'; + +@Component({ + selector: 'it-navscroll-custom-template-example', + templateUrl: './navscroll-custom-template-example.component.html', +}) +export class NavscrollCustomTemplateExampleComponent { + readonly header = 'Custom template example'; + readonly items = [ + { + title: 'Prima Sezione', + text: 'Testo prima sezione', + href: '#', + childs: [ + { + title: 'Sottosezione 1.1', + text: 'Testo sottosezione 1.1', + href: '#', + childs: [ + { + title: 'Sottosezione 1.1.1', + text: 'Testo sottosezione 1.1.1', + href: '#', + childs: [ + { + title: 'Sottosezione 1.1.1.1', + text: 'Testo sottosezione 1.1.1.1', + href: '#', + childs: [], + }, + ], + }, + { + title: 'Sottosezione 1.1.2', + text: 'Testo sottosezione 1.1.2', + href: '#', + childs: [], + }, + ], + }, + { + title: 'Sottosezione 1.2', + text: 'Testo sottosezione 1.2', + href: '#', + childs: [], + }, + { + title: 'Sottosezione 1.3', + text: 'Testo sottosezione 1.3', + href: '#', + childs: [], + }, + ], + }, + { + title: 'Seconda Sezione', + text: 'Testo seconda sezione', + href: '#', + childs: [ + { + title: 'Sottosezione 2.1', + text: 'Testo sottosezione 2.1', + href: '#', + childs: [], + }, + { + title: 'Sottosezione 2.2', + text: 'Testo sottosezione 2.2', + href: '#', + childs: [], + }, + ], + }, + ] satisfies NavscrollItems; +} diff --git a/src/app/navscroll/navscroll-default-example/navscroll-default-example.component.html b/src/app/navscroll/navscroll-default-example/navscroll-default-example.component.html new file mode 100644 index 00000000..30bd7798 --- /dev/null +++ b/src/app/navscroll/navscroll-default-example/navscroll-default-example.component.html @@ -0,0 +1 @@ + diff --git a/src/app/navscroll/navscroll-default-example/navscroll-default-example.component.ts b/src/app/navscroll/navscroll-default-example/navscroll-default-example.component.ts new file mode 100644 index 00000000..7612c317 --- /dev/null +++ b/src/app/navscroll/navscroll-default-example/navscroll-default-example.component.ts @@ -0,0 +1,76 @@ +import { Component } from '@angular/core'; +import { NavscrollItems } from 'projects/design-angular-kit/src/public_api'; + +@Component({ + selector: 'it-navscroll-default-example', + templateUrl: './navscroll-default-example.component.html', +}) +export class NavscrollDefaultExampleComponent { + readonly header = 'Default example'; + readonly items = [ + { + title: 'Prima Sezione', + text: 'Testo prima sezione', + href: '#', + childs: [ + { + title: 'Sottosezione 1.1', + text: 'Testo sottosezione 1.1', + href: '#', + childs: [ + { + title: 'Sottosezione 1.1.1', + text: 'Testo sottosezione 1.1.1', + href: '#', + childs: [ + { + title: 'Sottosezione 1.1.1.1', + text: 'Testo sottosezione 1.1.1.1', + href: '#', + childs: [], + }, + ], + }, + { + title: 'Sottosezione 1.1.2', + text: 'Testo sottosezione 1.1.2', + href: '#', + childs: [], + }, + ], + }, + { + title: 'Sottosezione 1.2', + text: 'Testo sottosezione 1.2', + href: '#', + childs: [], + }, + { + title: 'Sottosezione 1.3', + text: 'Testo sottosezione 1.3', + href: '#', + childs: [], + }, + ], + }, + { + title: 'Seconda Sezione', + text: 'Testo seconda sezione', + href: '#', + childs: [ + { + title: 'Sottosezione 2.1', + text: 'Testo sottosezione 2.1', + href: '#', + childs: [], + }, + { + title: 'Sottosezione 2.2', + text: 'Testo sottosezione 2.2', + href: '#', + childs: [], + }, + ], + }, + ] satisfies NavscrollItems; +} diff --git a/src/app/navscroll/navscroll-examples/navscroll-examples.component.scss b/src/app/navscroll/navscroll-examples/navscroll-examples.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/navscroll/navscroll-examples/navscroll-examples.component.tpl b/src/app/navscroll/navscroll-examples/navscroll-examples.component.tpl new file mode 100644 index 00000000..18945d94 --- /dev/null +++ b/src/app/navscroll/navscroll-examples/navscroll-examples.component.tpl @@ -0,0 +1,30 @@ +{% from "../../macro.template.njk" import sanitize as sanitize %} + +{% set htmlColor %} + {% include "../navscroll-default-example/navscroll-default-example.component.html" %} +{% endset %} + +{% set typescriptColor %} + {% include "../navscroll-default-example/navscroll-default-example.component.ts" %} +{% endset %} + +

Esempio di default

+ + + + + +{% set customTemplateHtmlColor %} + {% include "../navscroll-custom-template-example/navscroll-custom-template-example.component.html" %} +{% endset %} + +{% set customTemplateTypescriptColor %} + {% include "../navscroll-custom-template-example/navscroll-custom-template-example.component.ts" %} +{% endset %} + +

Esempio con template personalizzato

+ + + + + diff --git a/src/app/navscroll/navscroll-examples/navscroll-examples.component.ts b/src/app/navscroll/navscroll-examples/navscroll-examples.component.ts new file mode 100644 index 00000000..b405a8e1 --- /dev/null +++ b/src/app/navscroll/navscroll-examples/navscroll-examples.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'it-navscroll-examples', + templateUrl: './navscroll-examples.component.html', + styleUrl: './navscroll-examples.component.scss', +}) +export class NavscrollExamplesComponent {} diff --git a/src/app/navscroll/navscroll-index/navscroll-index.component.html b/src/app/navscroll/navscroll-index/navscroll-index.component.html new file mode 100644 index 00000000..87d8ea6c --- /dev/null +++ b/src/app/navscroll/navscroll-index/navscroll-index.component.html @@ -0,0 +1,12 @@ +

Navscroll

+

Componente che presenta liste di link con ancore a sezioni della pagina in cui รจ contenuto.

+
+

Esempio funzionante

+ + + + + + + + diff --git a/src/app/navscroll/navscroll-index/navscroll-index.component.ts b/src/app/navscroll/navscroll-index/navscroll-index.component.ts new file mode 100644 index 00000000..1a0d2455 --- /dev/null +++ b/src/app/navscroll/navscroll-index/navscroll-index.component.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; +import Documentation from '../../../assets/documentation.json'; + +@Component({ + selector: 'it-navscroll-index', + templateUrl: './navscroll-index.component.html', +}) +export class NavscrollIndexComponent { + component: any; + + constructor() { + this.component = (Documentation).components.find(component => component.name === 'ItNavscrollComponent'); + } +} diff --git a/src/app/navscroll/navscroll-routing.module.ts b/src/app/navscroll/navscroll-routing.module.ts new file mode 100644 index 00000000..ce6dd05c --- /dev/null +++ b/src/app/navscroll/navscroll-routing.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { NavscrollIndexComponent } from './navscroll-index/navscroll-index.component'; + +export const ROUTES = [{ path: '', component: NavscrollIndexComponent }] satisfies Routes; + +@NgModule({ + imports: [RouterModule.forChild(ROUTES)], + exports: [RouterModule], +}) +export class NavscrollRoutingModule {} diff --git a/src/app/navscroll/navscroll.module.ts b/src/app/navscroll/navscroll.module.ts new file mode 100644 index 00000000..ae323f9e --- /dev/null +++ b/src/app/navscroll/navscroll.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { SharedModule } from '../shared/shared.module'; +import { NavscrollDefaultExampleComponent } from './navscroll-default-example/navscroll-default-example.component'; +import { NavscrollExamplesComponent } from './navscroll-examples/navscroll-examples.component'; +import { NavscrollIndexComponent } from './navscroll-index/navscroll-index.component'; +import { NavscrollRoutingModule } from './navscroll-routing.module'; + +@NgModule({ + imports: [NavscrollRoutingModule, SharedModule], + declarations: [NavscrollIndexComponent, NavscrollExamplesComponent, NavscrollDefaultExampleComponent], +}) +export class NavscrollModule {} diff --git a/src/assets/table-of-content.json b/src/assets/table-of-content.json index cb284d99..e091ac80 100644 --- a/src/assets/table-of-content.json +++ b/src/assets/table-of-content.json @@ -187,6 +187,10 @@ "label": "Timeline", "link": "/componenti/timeline" }, + { + "label": "Navscroll", + "link": "/componenti/navscroll" + }, { "label": "Transfer", "link": "/componenti/transfer"