From acdc068357c0470575f26b33b47c882688c4be1a Mon Sep 17 00:00:00 2001 From: Kevin Davila <144152756+KevinDavilaDotCMS@users.noreply.github.com> Date: Fri, 6 Sep 2024 16:59:13 -0500 Subject: [PATCH] feat(sdk-angular): Improve documentation in @dotcms/angular and angular-example (#29884) ### Proposed Changes * Removed unused code * Moved some folders to improve code reading * Updated README in `@dotcms/angular` and `examples/angular` Note: I haven't updated the version number of the libs yet, I'll do it before the merge to avoid conflicts --------- Co-authored-by: Kevin Davila --- core-web/libs/sdk/angular/README.md | 206 +++++++++++------- core-web/libs/sdk/angular/package.json | 4 +- .../no-component/no-component.component.ts | 14 +- .../src/lib/layout/column/column.component.ts | 19 ++ .../layout/container/container.component.ts | 55 +++++ .../layout/contentlet/contentlet.component.ts | 67 ++++++ .../dotcms-layout/dotcms-layout.component.ts | 19 +- .../src/lib/layout/row/row.component.ts | 12 + .../libs/sdk/angular/src/lib/models/index.ts | 31 +++ .../libs/sdk/angular/src/lib/utils/index.ts | 22 ++ core-web/libs/sdk/client/package.json | 2 +- core-web/libs/sdk/experiments/package.json | 4 +- core-web/libs/sdk/react/package.json | 4 +- examples/angular/README.md | 168 ++++++++++---- examples/angular/package-lock.json | 25 +-- examples/angular/src/app/app.component.ts | 2 +- .../activity/activity.component.css | 0 .../activity/activity.component.ts | 0 .../content-types/banner/banner.component.css | 0 .../content-types/banner/banner.component.ts | 0 .../custom-no-component.component.ts | 18 ++ .../content-types/image/image.component.css | 0 .../content-types/image/image.component.ts | 0 .../product/product.component.css | 0 .../product/product.component.ts | 1 - .../web-page-content.component.css | 0 .../web-page-content.component.ts | 0 .../footer}/blogs/blogs.component.ts | 13 +- .../destinations/destinations.component.ts | 11 +- .../components/footer/footer.component.ts | 7 +- .../src/app/{ => pages}/components/index.ts | 12 +- .../custom-no-component.component.ts | 15 -- .../angular/src/app/pages/pages.component.ts | 3 +- .../contentlet/contentlet.component.ts | 10 +- .../contentlets.component.ts | 21 +- 35 files changed, 568 insertions(+), 197 deletions(-) rename examples/angular/src/app/{pages => }/content-types/activity/activity.component.css (100%) rename examples/angular/src/app/{pages => }/content-types/activity/activity.component.ts (100%) rename examples/angular/src/app/{pages => }/content-types/banner/banner.component.css (100%) rename examples/angular/src/app/{pages => }/content-types/banner/banner.component.ts (100%) create mode 100644 examples/angular/src/app/content-types/custom-no-component/custom-no-component.component.ts rename examples/angular/src/app/{pages => }/content-types/image/image.component.css (100%) rename examples/angular/src/app/{pages => }/content-types/image/image.component.ts (100%) rename examples/angular/src/app/{pages => }/content-types/product/product.component.css (100%) rename examples/angular/src/app/{pages => }/content-types/product/product.component.ts (99%) rename examples/angular/src/app/{pages => }/content-types/web-page-content/web-page-content.component.css (100%) rename examples/angular/src/app/{pages => }/content-types/web-page-content/web-page-content.component.ts (100%) rename examples/angular/src/app/{components => pages/components/footer}/blogs/blogs.component.ts (76%) rename examples/angular/src/app/{components => pages/components/footer}/destinations/destinations.component.ts (76%) rename examples/angular/src/app/{ => pages}/components/index.ts (58%) delete mode 100644 examples/angular/src/app/pages/content-types/custom-no-component/custom-no-component.component.ts rename examples/angular/src/app/{components => shared/contentlets-wrapper}/contentlet/contentlet.component.ts (75%) rename examples/angular/src/app/{components/contentlets => shared/contentlets-wrapper}/contentlets.component.ts (79%) diff --git a/core-web/libs/sdk/angular/README.md b/core-web/libs/sdk/angular/README.md index ebcea1845446..14d9cb3aced0 100644 --- a/core-web/libs/sdk/angular/README.md +++ b/core-web/libs/sdk/angular/README.md @@ -1,17 +1,31 @@ # @dotcms/angular -`@dotcms/angular` is the official set of Angular components, services and resolver designed to work seamlessly with dotCMS, making it easy to render dotCMS pages an use the page builder +`@dotcms/angular` is the official Angular library designed to work seamlessly with dotCMS. This library simplifies the process of rendering dotCMS pages and integrating with the [Universal Visual Editor](dotcms.com/docs/latest/universal-visual-editor) in your Angular applications. + +## Table of Contents + +- [Features](#features) +- [Installation](#installation) +- [Configuration](#provider-setup) + - [Provider Setup](#provider-setup) + - [Client Usage](#client-usage) +- [Components](#components) + - [DotcmsLayoutComponent](#dotcmslayoutcomponent) +- [Best Practices](#best-practices) +- [Troubleshooting](#troubleshooting) +- [Contributing](#contributing) +- [Licensing](#licensing) ## Features -- A collection of Angular components, services and resolver tailored to render - dotCMS pages. -- Streamlined integration with dotCMS page editor. -- Improved development experience with comprehensive TypeScript typings. +- A set of Angular components developer for dotCMS page rendering and editor integration. +- Enhanced development workflow with full TypeScript support. +- Optimized performance for efficient rendering of dotCMS pages in Angular applications. +- Flexible customization options to adapt to various project requirements. ## Installation -Install the package via npm: +Install the package using npm: ```bash npm install @dotcms/angular @@ -23,111 +37,147 @@ Or using Yarn: yarn add @dotcms/angular ``` -## Provider -``` +## Configutarion +### Provider Setup +We need to provide the information of our dotCMS instance + +```javascript + +import { ClientConfig } from '@dotcms/client'; + const DOTCMS_CLIENT_CONFIG: ClientConfig = { dotcmsUrl: environment.dotcmsUrl, authToken: environment.authToken, siteId: environment.siteId }; ``` -Add the dotcms config in the Angular app ApplicationConfig -``` +And add this config in the Angular app ApplicationConfig. + +`src/app/app.config.ts` +```javascript +import { InjectionToken } from '@angular/core'; +import { ClientConfig, DotCmsClient } from '@dotcms/client'; + +export const DOTCMS_CLIENT_TOKEN = new InjectionToken('DOTCMS_CLIENT'); + export const appConfig: ApplicationConfig = { providers: [ - provideDotcmsClient(DOTCMS_CLIENT_CONFIG), provideRouter(routes), + { + provide: DOTCMS_CLIENT_TOKEN, + useValue: DotCmsClient.init(DOTCMS_CLIENT_CONFIG), + } ], }; ``` -## Resolver -```javascript -export const routes: Routes = [ - { - path: '**', - resolve: { - // This should be called `context`. - context: DotCMSPageResolver, - }, - component: DotCMSPagesComponent, - runGuardsAndResolvers: 'always' // Run the resolver on every navigation. Even if the URL hasn't changed. - }, -]; -``` +This way, we will have access to `DOTCMS_CLIENT_TOKEN` from anywhere in our application. -Then, in your component, you can read the data using +### Client Usage +To interact with the client and obtain information from, for example, our pages ```javascript -protected readonly context = signal(null); - -ngOnInit() { - // Get the context data from the route - this.route.data.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(data => { - this.context.set(data['context']); - }); -} +private readonly client = inject(DOTCMS_CLIENT_TOKEN); + +this.client.page + .get({ ...pageParams }) + .then((response) => { + // Use your response + }) + .catch((e) => { + const error: PageError = { + message: e.message, + status: e.status, + }; + // Use the error response + }) ``` -## Components +For more information to how to use DotCms Client, you can visit the [documentation](https://github.com/dotCMS/core/blob/master/core-web/libs/sdk/client/README.md) -### `DotcmsLayoutComponent` +## DotCMS Page API -A component that renders a layout for a dotCMS page. +The `DotcmsLayoutComponent` requires a `DotCMSPageAsset` object to be passed in to it. This object represents a dotCMS page and can be fetched using the `@dotcms/client` library. -#### Inputs +- [DotCMS Official Angular Example](https://github.com/dotCMS/core/tree/master/examples/angular) +- [`@dotcms/client` documentation](https://www.npmjs.com/package/@dotcms/client) +- [Page API documentation](https://dotcms.com/docs/latest/page-api) -- **entity**: The context for a dotCMS page. -- **components**: An object with the relation of contentlets and the component to render each. +## Components +### DotcmsLayoutComponent -#### Usage +The `DotcmsLayoutComponent` is a crucial component for rendering dotCMS page layouts in your Angular application. -```javascript - - - DYNAMIC_COMPONENTS: { [key: string]: DynamicComponentEntity } = { - Activity: import('../pages/content-types/activity/activity.component').then( - (c) => c.ActivityComponent, - ), - Banner: import('../pages/content-types/banner/banner.component').then( - (c) => c.BannerComponent, - ), - Image: import('../pages/content-types/image/image.component').then( - (c) => c.ImageComponent, - ), - webPageContent: import( - '../pages/content-types/web-page-content/web-page-content.component' - ).then((c) => c.WebPageContentComponent), - Product: import('../pages/content-types/product/product.component').then( - (c) => c.ProductComponent, - ), +#### Inputs + +| Name | Type | Description | +|--------------|----------------------|-----------------------------------------------------------------------| +| `pageAsset` | `DotCMSPageAsset` | The object representing a dotCMS page from PageAPI response. | +| `components` | `DotCMSPageComponent`| An object mapping contentlets to their respective render components. | +| `editor` | `EditorConfig` | Configuration for data fetching in Edit Mode. | + +#### Usage Example + +In your component file (e.g., `pages.component.ts`): + +```typescript +import { Component, signal } from '@angular/core'; +import { DotCMSPageComponent, EditorConfig } from '@dotcms/angular'; + +@Component({ + selector: 'app-pages', + templateUrl: './pages.component.html', +}) +export class PagesComponent { + DYNAMIC_COMPONENTS: DotCMSPageComponent = { + Activity: import('../pages/content-types/activity/activity.component').then( + (c) => c.ActivityComponent + ), + Banner: import('../pages/content-types/banner/banner.component').then( + (c) => c.BannerComponent + ), + // Add other components as needed }; + + components = signal(this.DYNAMIC_COMPONENTS); + editorConfig = signal({ params: { depth: 2 } }); + + // Assume pageAsset is fetched or provided somehow + pageAsset: DotCMSPageAsset; +} +``` -components = signal(DYNAMIC_COMPONENTS); +In your template file (e.g., `pages.component.html`): + +```html + ``` -## Contributing +This setup allows for dynamic rendering of different content types on your dotCMS pages. -GitHub pull requests are the preferred method to contribute code to dotCMS. Before any pull requests can be accepted, an automated tool will ask you to agree to the [dotCMS Contributor's Agreement](https://gist.github.com/wezell/85ef45298c48494b90d92755b583acb3). +## Best Practices -## Licensing +1. **Lazy Loading**: Use dynamic imports for components to improve initial load times. +2. **Error Handling**: Implement robust error handling for API calls and component rendering. +3. **Type Safety**: Leverage TypeScript's type system to ensure proper usage of dotCMS structures. +4. **Performance Optimization**: Monitor and optimize the performance of rendered components. -dotCMS comes in multiple editions and as such is dual licensed. The dotCMS Community Edition is licensed under the GPL 3.0 and is freely available for download, customization and deployment for use within organizations of all stripes. dotCMS Enterprise Editions (EE) adds a number of enterprise features and is available via a supported, indemnified commercial license from dotCMS. For the differences between the editions, see [the feature page](http://dotcms.com/cms-platform/features). +## Troubleshooting -## Support +If you encounter issues: -If you need help or have any questions, please [open an issue](https://github.com/dotCMS/core/issues/new/choose) in the GitHub repository. +1. Ensure all dependencies are correctly installed and up to date. +2. Verify that your dotCMS configuration (URL, auth token, site ID) is correct. +3. Check the browser console for any error messages. +4. Refer to the [dotCMS documentation](https://dotcms.com/docs/) for additional guidance. -## Documentation +## Contributing -Always refer to the official [DotCMS documentation](https://www.dotcms.com/docs/latest/) for comprehensive guides and API references. +GitHub pull requests are the preferred method to contribute code to dotCMS. Before any pull requests can be accepted, an automated tool will ask you to agree to the [dotCMS Contributor's Agreement](https://gist.github.com/wezell/85ef45298c48494b90d92755b583acb3). -## Getting Help +## Licensing -| Source | Location | -| --------------- | ------------------------------------------------------------------- | -| Installation | [Installation](https://dotcms.com/docs/latest/installation) | -| Documentation | [Documentation](https://dotcms.com/docs/latest/table-of-contents) | -| Videos | [Helpful Videos](http://dotcms.com/videos/) | -| Forums/Listserv | [via Google Groups](https://groups.google.com/forum/#!forum/dotCMS) | -| Twitter | @dotCMS | -| Main Site | [dotCMS.com](https://dotcms.com/) | +dotCMS comes in multiple editions and as such is dual licensed. The dotCMS Community Edition is licensed under the GPL 3.0 and is freely available for download, customization and deployment for use within organizations of all stripes. dotCMS Enterprise Editions (EE) adds a number of enterprise features and is available via a supported, indemnified commercial license from dotCMS. For the differences between the editions, see [the feature page](http://dotcms.com/cms-platform/features). \ No newline at end of file diff --git a/core-web/libs/sdk/angular/package.json b/core-web/libs/sdk/angular/package.json index 07f487d304e6..a280014e2c8c 100644 --- a/core-web/libs/sdk/angular/package.json +++ b/core-web/libs/sdk/angular/package.json @@ -1,11 +1,11 @@ { "name": "@dotcms/angular", - "version": "0.0.1-alpha.37", + "version": "0.0.1-alpha.38", "peerDependencies": { "@angular/common": "^17.1.0", "@angular/core": "^17.1.0", "@angular/router": "^17.1.0", - "@dotcms/client": "0.0.1-alpha.37", + "@dotcms/client": "0.0.1-alpha.38", "@tinymce/tinymce-angular": "^8.0.0", "rxjs": "^7.8.0" }, diff --git a/core-web/libs/sdk/angular/src/lib/components/no-component/no-component.component.ts b/core-web/libs/sdk/angular/src/lib/components/no-component/no-component.component.ts index 2d42d04cf1f7..b84e22f8e9e6 100644 --- a/core-web/libs/sdk/angular/src/lib/components/no-component/no-component.component.ts +++ b/core-web/libs/sdk/angular/src/lib/components/no-component/no-component.component.ts @@ -3,8 +3,10 @@ import { ChangeDetectionStrategy, Component, HostBinding, Input } from '@angular import { DotCMSContentlet } from '../../models'; /** - * This is part of the Angular SDK. - * This is a component for the `NoComponentComponent` component. + * This component is responsible to display a message when there is no component for a contentlet. + * + * @export + * @class NoComponent */ @Component({ selector: 'dotcms-no-component', @@ -16,6 +18,14 @@ import { DotCMSContentlet } from '../../models'; changeDetection: ChangeDetectionStrategy.OnPush }) export class NoComponent { + /** + * The contentlet object containing content data. + * The component displays a message based on the content type of this contentlet. + */ @Input() contentlet!: DotCMSContentlet; + + /** + * The data-testid attribute used for identifying the component during testing. + */ @HostBinding('attr.data-testid') testId = 'no-component'; } diff --git a/core-web/libs/sdk/angular/src/lib/layout/column/column.component.ts b/core-web/libs/sdk/angular/src/lib/layout/column/column.component.ts index 487fbf7a6eb1..6b7653d86f2e 100644 --- a/core-web/libs/sdk/angular/src/lib/layout/column/column.component.ts +++ b/core-web/libs/sdk/angular/src/lib/layout/column/column.component.ts @@ -4,6 +4,13 @@ import { DotPageAssetLayoutColumn } from '../../models'; import { getPositionStyleClasses } from '../../utils'; import { ContainerComponent } from '../container/container.component'; +/** + * This component is responsible to display a column with containers. + * + * @export + * @class ColumnComponent + * @implements {OnInit} + */ @Component({ selector: 'dotcms-column', standalone: true, @@ -17,7 +24,19 @@ import { ContainerComponent } from '../container/container.component'; changeDetection: ChangeDetectionStrategy.OnPush }) export class ColumnComponent implements OnInit { + /** + * The column object containing the containers. + * + * @type {DotPageAssetLayoutColumn} + * @memberof ColumnComponent + */ @Input() column!: DotPageAssetLayoutColumn; + + /** + * The data-testid attribute used for identifying the component during testing. + * + * @memberof ColumnComponent + */ @HostBinding('class') containerClasses = ''; ngOnInit() { diff --git a/core-web/libs/sdk/angular/src/lib/layout/container/container.component.ts b/core-web/libs/sdk/angular/src/lib/layout/container/container.component.ts index e8d6b2ed9bed..b74c3ea7804e 100644 --- a/core-web/libs/sdk/angular/src/lib/layout/container/container.component.ts +++ b/core-web/libs/sdk/angular/src/lib/layout/container/container.component.ts @@ -25,6 +25,13 @@ interface DotContainer { variantId?: string; } +/** + * This component is responsible to display a container with contentlets. + * + * @export + * @class ContainerComponent + * @implements {OnChanges} + */ @Component({ selector: 'dotcms-container', standalone: true, @@ -34,6 +41,12 @@ interface DotContainer { changeDetection: ChangeDetectionStrategy.OnPush }) export class ContainerComponent implements OnChanges { + /** + * The container object containing the contentlets. + * + * @type {DotCMSContainer} + * @memberof ContainerComponent + */ @Input({ required: true }) container!: DotCMSContainer; private readonly pageContextService: PageContextService = inject(PageContextService); @@ -45,12 +58,54 @@ export class ContainerComponent implements OnChanges { protected $dotContainer = signal(null); protected $dotContainerAsString = computed(() => JSON.stringify(this.$dotContainer())); + /** + * The accept types for the container component. + * + * @type {(string | null)} + * @memberof ContainerComponent + */ @HostBinding('attr.data-dot-accept-types') acceptTypes: string | null = null; + + /** + * The identifier for the container component. + * + * @type {(string | null)} + * @memberof ContainerComponent + */ @HostBinding('attr.data-dot-identifier') identifier: string | null = null; + /** + * The max contentlets for the container component. + * + * @type {(number | null)} + * @memberof ContainerComponent + */ @HostBinding('attr.data-max-contentlets') maxContentlets: number | null = null; + /** + * The uuid for the container component. + * + * @type {(string | null)} + * @memberof ContainerComponent + */ @HostBinding('attr.data-dot-uuid') uuid: string | null = null; + /** + * The class for the container component. + * + * @type {(string | null)} + * @memberof ContainerComponent + */ @HostBinding('class') class: string | null = null; + /** + * The dot object for the container component. + * + * @type {(string | null)} + * @memberof ContainerComponent + */ @HostBinding('attr.data-dot-object') dotObject: string | null = null; + /** + * The data-testid attribute used for identifying the component during testing. + * + * @memberof ContainerComponent + */ @HostBinding('attr.data-testid') testId = 'dot-container'; ngOnChanges() { diff --git a/core-web/libs/sdk/angular/src/lib/layout/contentlet/contentlet.component.ts b/core-web/libs/sdk/angular/src/lib/layout/contentlet/contentlet.component.ts index f462f23ea9da..98c1ac999de0 100644 --- a/core-web/libs/sdk/angular/src/lib/layout/contentlet/contentlet.component.ts +++ b/core-web/libs/sdk/angular/src/lib/layout/contentlet/contentlet.component.ts @@ -2,6 +2,13 @@ import { ChangeDetectionStrategy, Component, HostBinding, Input, OnChanges } fro import { DotCMSContentlet } from '../../models'; +/** + * This component is responsible to display a contentlet. + * + * @export + * @class ContentletComponent + * @implements {OnChanges} + */ @Component({ selector: 'dotcms-contentlet-wrapper', standalone: true, @@ -9,16 +16,76 @@ import { DotCMSContentlet } from '../../models'; changeDetection: ChangeDetectionStrategy.OnPush }) export class ContentletComponent implements OnChanges { + /** + * The contentlet object containing content data. + * + * @type {DotCMSContentlet} + * @memberof ContentletComponent + */ @Input({ required: true }) contentlet!: DotCMSContentlet; + /** + * The container data (as string) where the contentlet is located. + * + * @type {string} + * @memberof ContentletComponent + */ @Input() container!: string; + /** + * The identifier of contentlet component. + * + * @type {(string | null)} + * @memberof ContentletComponent + */ @HostBinding('attr.data-dot-identifier') identifier: string | null = null; + /** + * The base type of contentlet component. + * + * @type {(string | null)} + * @memberof ContentletComponent + */ @HostBinding('attr.data-dot-basetype') baseType: string | null = null; + /** + * The title of contentlet component. + * + * @type {(string | null)} + * @memberof ContentletComponent + */ @HostBinding('attr.data-dot-title') title: string | null = null; + /** + * The inode of contentlet component. + * + * @type {(string | null)} + * @memberof ContentletComponent + */ @HostBinding('attr.data-dot-inode') inode: string | null = null; + /** + * The type of contentlet component. + * + * @type {(string | null)} + * @memberof ContentletComponent + */ @HostBinding('attr.data-dot-type') dotType: string | null = null; + /** + * The container of contentlet component. + * + * @type {(string | null)} + * @memberof ContentletComponent + */ @HostBinding('attr.data-dot-container') dotContainer: string | null = null; + /** + * The number of pages where the contentlet appears + * + * @type {(string | null)} + * @memberof ContentletComponent + */ @HostBinding('attr.data-dot-on-number-of-pages') numberOfPages: string | null = null; + /** + * The content of contentlet component. + * + * @type {(string | null)} + * @memberof ContentletComponent + */ @HostBinding('attr.data-dot-object') dotContent: string | null = null; ngOnChanges() { diff --git a/core-web/libs/sdk/angular/src/lib/layout/dotcms-layout/dotcms-layout.component.ts b/core-web/libs/sdk/angular/src/lib/layout/dotcms-layout/dotcms-layout.component.ts index ccab80606513..51aeb6d115e5 100644 --- a/core-web/libs/sdk/angular/src/lib/layout/dotcms-layout/dotcms-layout.component.ts +++ b/core-web/libs/sdk/angular/src/lib/layout/dotcms-layout/dotcms-layout.component.ts @@ -20,7 +20,7 @@ import { updateNavigation } from '@dotcms/client'; -import { DynamicComponentEntity } from '../../models'; +import { DotCMSPageComponent } from '../../models'; import { DotCMSPageAsset } from '../../models/dotcms.model'; import { PageContextService } from '../../services/dotcms-context/page-context.service'; import { RowComponent } from '../row/row.component'; @@ -49,6 +49,12 @@ import { RowComponent } from '../row/row.component'; export class DotcmsLayoutComponent implements OnInit { private _pageAsset!: DotCMSPageAsset; + /** + * Represents the DotCMS page asset. + * + * @type {DotCMSPageAsset} + * @memberof DotcmsLayoutComponent + */ @Input({ required: true }) set pageAsset(value: DotCMSPageAsset) { this._pageAsset = value; @@ -59,6 +65,13 @@ export class DotcmsLayoutComponent implements OnInit { } } + /** + * Returns the DotCMS page asset. + * + * @readonly + * @type {DotCMSPageAsset} + * @memberof DotcmsLayoutComponent + */ get pageAsset(): DotCMSPageAsset { return this._pageAsset; } @@ -66,11 +79,11 @@ export class DotcmsLayoutComponent implements OnInit { /** * The `components` property is a record of dynamic components for each Contentlet on the page. * - * @type {Record} + * @type {DotCMSPageComponent} * @memberof DotcmsLayoutComponent * @required */ - @Input({ required: true }) components!: Record; + @Input({ required: true }) components!: DotCMSPageComponent; /** * The `onReload` property is a function that reloads the page after changes are made. diff --git a/core-web/libs/sdk/angular/src/lib/layout/row/row.component.ts b/core-web/libs/sdk/angular/src/lib/layout/row/row.component.ts index 2c7dd66c2732..ab5cd0e7389d 100644 --- a/core-web/libs/sdk/angular/src/lib/layout/row/row.component.ts +++ b/core-web/libs/sdk/angular/src/lib/layout/row/row.component.ts @@ -3,6 +3,12 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { DotPageAssetLayoutRow } from '../../models'; import { ColumnComponent } from '../column/column.component'; +/** + * This component is responsible to display a row with columns. + * + * @export + * @class RowComponent + */ @Component({ selector: 'dotcms-row', standalone: true, @@ -16,5 +22,11 @@ import { ColumnComponent } from '../column/column.component'; changeDetection: ChangeDetectionStrategy.OnPush }) export class RowComponent { + /** + * The row object containing the columns. + * + * @type {DotPageAssetLayoutRow} + * @memberof RowComponent + */ @Input({ required: true }) row!: DotPageAssetLayoutRow; } diff --git a/core-web/libs/sdk/angular/src/lib/models/index.ts b/core-web/libs/sdk/angular/src/lib/models/index.ts index 31407bfd90b8..ce9ff860b3b8 100644 --- a/core-web/libs/sdk/angular/src/lib/models/index.ts +++ b/core-web/libs/sdk/angular/src/lib/models/index.ts @@ -5,12 +5,43 @@ import { Type } from '@angular/core'; import { DotCMSPageAsset } from './dotcms.model'; +/** + * Represents a dynamic component entity. + * @typedef {Promise>} DynamicComponentEntity + * @memberof @dotcms/angular + */ export type DynamicComponentEntity = Promise>; +/** + * Represents the context of a DotCMS page. + */ export interface DotCMSPageContext { + /** + * Represents the DotCMS page asset. + * @type {DotCMSPageAsset} + * @memberof DotCMSPageContext + */ pageAsset: DotCMSPageAsset; + + /** + * Represents the dynamic components of the page for each Content Type. + * @type {DotCMSPageComponent} + * @memberof DotCMSPageContext + */ components: DotCMSPageComponent; + + /** + * Indicates whether the page is being viewed inside the editor. + * @type {boolean} + * @memberof DotCMSPageContext + */ isInsideEditor: boolean; } +/** + * Represents a DotCMS page component. + * Used to store the dynamic components of a DotCMS page. + * @typedef {Record} DotCMSPageComponent + * @memberof @dotcms/angular + */ export type DotCMSPageComponent = Record; diff --git a/core-web/libs/sdk/angular/src/lib/utils/index.ts b/core-web/libs/sdk/angular/src/lib/utils/index.ts index 7ef070738a62..fd9f44de7c33 100644 --- a/core-web/libs/sdk/angular/src/lib/utils/index.ts +++ b/core-web/libs/sdk/angular/src/lib/utils/index.ts @@ -2,6 +2,10 @@ import { DotCMSContainer, DotCMSPageAssetContainer } from '../models/dotcms.mode //Changed the type, to avoid SQ issue. //This should be put inside a lib +/** + * Represents a mapping of numbers to corresponding CSS class names for column end values. + * @typedef {Record} EndClassMap + */ const endClassMap: Record = { 1: 'col-end-1', 2: 'col-end-2', @@ -20,6 +24,10 @@ const endClassMap: Record = { //Changed the type, to avoid SQ issue. //This should be put inside a lib +/** + * Represents a mapping of numbers to CSS class names for starting columns. + * @typedef {Record} StartClassMap + */ const startClassMap: Record = { 1: 'col-start-1', 2: 'col-start-2', @@ -35,6 +43,13 @@ const startClassMap: Record = { 12: 'col-start-12' }; +/** + * Retrieves the data for a set of containers. + * + * @param containers - The DotCMSPageAssetContainer object containing the containers. + * @param containerRef - The DotCMSContainer object representing the container reference. + * @returns An object containing the container data, accept types, contentlets, and variant ID. + */ export const getContainersData = ( containers: DotCMSPageAssetContainer, containerRef: DotCMSContainer @@ -59,6 +74,13 @@ export const getContainersData = ( }; }; +/** + * Returns the position style classes based on the start and end values. + * Used to set the grid column start and end values. + * @param start - The start value. + * @param end - The end value. + * @returns An object containing the startClass and endClass. + */ export const getPositionStyleClasses = (start: number, end: number) => { const startClass = startClassMap[start]; const endClass = endClassMap[end]; diff --git a/core-web/libs/sdk/client/package.json b/core-web/libs/sdk/client/package.json index 10f66719bcaf..6bff51d59be9 100644 --- a/core-web/libs/sdk/client/package.json +++ b/core-web/libs/sdk/client/package.json @@ -1,6 +1,6 @@ { "name": "@dotcms/client", - "version": "0.0.1-alpha.37", + "version": "0.0.1-alpha.38", "description": "Official JavaScript library for interacting with DotCMS REST APIs.", "repository": { "type": "git", diff --git a/core-web/libs/sdk/experiments/package.json b/core-web/libs/sdk/experiments/package.json index fc3b1d608ae8..c1179a480328 100644 --- a/core-web/libs/sdk/experiments/package.json +++ b/core-web/libs/sdk/experiments/package.json @@ -1,6 +1,6 @@ { "name": "@dotcms/experiments", - "version": "0.0.1-alpha.37", + "version": "0.0.1-alpha.38", "description": "Official JavaScript library to use Experiments with DotCMS.", "repository": { "type": "git", @@ -25,6 +25,6 @@ "peerDependencies": { "react": ">=18", "react-dom": ">=18", - "@dotcms/client": "0.0.1-alpha.37" + "@dotcms/client": "0.0.1-alpha.38" } } diff --git a/core-web/libs/sdk/react/package.json b/core-web/libs/sdk/react/package.json index 056f59f36cd1..5011c2faf8f8 100644 --- a/core-web/libs/sdk/react/package.json +++ b/core-web/libs/sdk/react/package.json @@ -1,10 +1,10 @@ { "name": "@dotcms/react", - "version": "0.0.1-alpha.37", + "version": "0.0.1-alpha.38", "peerDependencies": { "react": ">=18", "react-dom": ">=18", - "@dotcms/client": "0.0.1-alpha.37", + "@dotcms/client": "0.0.1-alpha.38", "@tinymce/tinymce-react": "^5.1.1" }, "description": "Official React Components library to render a dotCMS page.", diff --git a/examples/angular/README.md b/examples/angular/README.md index 5bc85127d6c1..90c2c58417dc 100644 --- a/examples/angular/README.md +++ b/examples/angular/README.md @@ -1,64 +1,152 @@ -# dotCMS Angular Example +# dotCMS Angular Example -DotCMS provides an Angular example that shows how to build manageable dotCMS pages headlessly with the Angular JavaScript framework. +This example project demonstrates how to build manageable dotCMS pages headlessly using the Angular framework. It showcases the integration between dotCMS and Angular, providing a practical implementation of content-driven web applications. -## What do you need? +## Table of Contents -1. A dotCMS instance or you can use https://demo.dotcms.com -2. A valid AUTH token for the target instance (see: https://auth.dotcms.com/docs/latest/rest-api-authentication#creating-an-api-token-in-the-ui) -3. Node js 18+ and npm installed -4. Terminal -5. And a code editor. +- [Prerequisites](#prerequisites) +- [Getting Started](#getting-started) + - [Obtaining the Example Code](#downloading-the-example) + - [Configuration](#configuration) +- [Running the Application](#running-the-application) +- [Project Structure](#project-structure) +- [Key Features](#handling-vanity-urls) + - [Handling Vanity URLs](#handling-vanity-urls) +- [Troubleshooting](#troubleshooting) +- [Further Resources](#further-resources) -### Get the Angular example code +## Prerequisites -Get the code from the Angular example directory +Before you begin, ensure you have the following: -```bash -https://github.com/dotCMS/core/tree/master/examples/angular -``` +1. Access to a dotCMS instance (you can use https://demo.dotcms.com if you don't have your own) +2. A valid AUTH token for the target dotCMS instance ([How to create an API token](https://auth.dotcms.com/docs/latest/rest-api-authentication#creating-an-api-token-in-the-ui)) +3. Node.js (version 18 or higher) and npm installed +4. A terminal application +5. A code editor of your choice -Or just checkout the directory +## Getting Started -```bash -git clone -n --depth=1 --filter=tree:0 https://github.com/dotCMS/core -cd core -git sparse-checkout set --no-cone examples/angular -git checkout -``` -The files will be found under the `examples/angular` folder +### Downloading the example + +You can get the code in two ways: + +1. Direct download: + ``` + https://github.com/dotCMS/core/tree/master/examples/angular + ``` + +2. Using Git sparse checkout: + ```bash + git clone -n --depth=1 --filter=tree:0 https://github.com/dotCMS/core + cd core + git sparse-checkout set --no-cone examples/angular + git checkout + ``` + The example files will be in the `examples/angular` folder. + +### Configuration + +To configure the Angular app to use your dotCMS instance: + +1. Open the project folder in your code editor +2. Navigate to `src/environments` +3. Open `environment.development.ts` and update the following variables: + - `authToken`: Your dotCMS auth token + - `dotcmsUrl`: URL of your dotCMS instance (e.g., https://demo.dotcms.com) + ```typescript + export const environment = { + production: false, + authToken: 'YOUR_AUTH_TOKEN_HERE', + dotcmsUrl: 'https://demo.dotcms.com', + }; + ``` + ⚠️ **Security Note**: Ensure that the `authToken` used here has [read-only permissions](https://www.dotcms.com/docs/latest/user-permissions#FrontEndBackEnd) to minimize security risks in client-side applications. -## Add the dotCMS configuration +## Running the Application -Now we need to tell the Angular app what dotCMS instance is going to use to get the data to build its pages. +Once configured, follow these steps to run the app: -1. Open the folder `YOUR_NAME` in your code editor -2. Go to `src/environments` -3. Open the `environment.development.ts` file and update the environment variable: +1. Open a terminal in the project root directory +2. Install dependencies: `npm install` +3. Start the development server: `ng serve` +4. Open your browser and navigate to `http://localhost:4200` + +πŸŽ‰ Congratulations! Your dotCMS Angular example is now running. + +Note: When accessing `localhost:4200/about`, ensure that the `/about` page exists in your dotCMS instance. + +## Project Structure + +``` +. +└── src/ + └── app/ + β”œβ”€β”€ content-types/ + β”‚ β”œβ”€β”€ activity + β”‚ β”œβ”€β”€ banner + β”‚ β”œβ”€β”€ product + β”‚ └── ...other-content-types + β”œβ”€β”€ pages/ + β”‚ β”œβ”€β”€ components + β”‚ └── services + └── shared/ + └── contentlets-wrapper/ + └── contentlet/ +``` + +- `content-types/`: Components for rendering specific dotCMS content types +- `pages/`: Main application component for rendering pages based on their path and pageAsset +- `shared/`: Reusable components + - `contentlets-wrapper/`: Component for displaying lists of Contentlets + - `contentlet/`: Component for rendering individual Contentlets + +## Universal Visual Editor +To enable the Universal Visual Editor in dotCMS, follow these steps: + +1. In your dotCMS instance, navigate to the "Apps" page +2. Find the "UVE - Universal Visual Editor" app and click on it +3. Then locate the site where you want to enable the UVE and click on it +4. In the configuration field add the following: + +```json +{ + "config": [ + { + "pattern": ".*", + "url": "http://localhost:4200" + } + ] +} +``` -- `authToken` this is the auth token for dotCMS, you can use the dotCMS UI to create one. -- `dotcmsUrl` this is the instance of dotCMS where your pages and content lives (license needed) if you don’t have one, you can use [https://demo.dotcms.com](https://demo.dotcms.com) (be careful it restarts every 24h) +5. Click on the "Save" button to save the changes. +6. Now edit any page and you will see the UVE. -## Run the app +If you want more information about the UVE, please refer to the [dotCMS UVE Documentation](https://dotcms.com/docs/latest/universal-visual-editor-uve). -Once all the configuration is in place, it is time to run the web app. +## Key Features +### Handling Vanity URLs -1. Go back to your terminal and from the folder YOUR_NAME -2. Run `ng serve` -3. Open http://localhost:4200 in your browser +This example demonstrates how to integrate dotCMS Vanity URLs with Angular routing. Vanity URLs in dotCMS provide alternative paths to internal or external URLs, enhancing site maintenance and SEO. -πŸŽ‰ And that’s it. +For implementation details, refer to the [`DotCMSPagesComponent`](./src/app/pages/components/dotcms-pages/dotcms-pages.component.ts) in the example code, which handles routing and Vanity URL redirection. -Consider that if you go to `localhost:4200/about`, the page `/about` needs to exist in your dotCMS instance. +## Troubleshooting -## Handling Vanity URLs +If you encounter issues: -In dotCMS, Vanity URLs serve as alternative reference paths to internal or external URLs. They are simple yet powerful tools that can significantly aid in site maintenance and SEO. +1. Verify that your dotCMS instance is accessible and the AUTH token is valid +2. Check the browser console for any error messages +3. Ensure all dependencies are correctly installed (`npm install`) +4. Verify that the required pages and content exist in your dotCMS instance -Next.js is a robust framework that provides the capability to handle vanity URLs. It allows you to redirect or forward users to the appropriate content based on predefined logic. You can seamlessly integrate this feature of Next.js with dotCMS. For an implementation example, refer to this [link](https://github.com/dotCMS/core/blob/master/examples/nextjs/src/app/utils/index.js). +## Further Resources -## Further help +- [Angular CLI Documentation](https://angular.io/cli) +- [dotCMS Documentation](https://dotcms.com/docs/) +- [dotCMS REST API Authentication](https://auth.dotcms.com/docs/latest/rest-api-authentication) -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. +For more assistance with Angular, use `ng help` or visit the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. \ No newline at end of file diff --git a/examples/angular/package-lock.json b/examples/angular/package-lock.json index c0f3f19a13a0..15e236515a51 100644 --- a/examples/angular/package-lock.json +++ b/examples/angular/package-lock.json @@ -16,9 +16,8 @@ "@angular/platform-browser": "^17.1.0", "@angular/platform-browser-dynamic": "^17.1.0", "@angular/router": "^17.1.0", - "@dotcms/angular": "0.0.1-alpha.34", - "@dotcms/client": "0.0.1-alpha.34", - "@tinymce/tinymce-angular": "^8.0.0", + "@dotcms/angular": "0.0.1-alpha.37", + "@dotcms/client": "0.0.1-alpha.37", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.14.2" @@ -2535,10 +2534,9 @@ } }, "node_modules/@dotcms/angular": { - "version": "0.0.1-alpha.34", - "resolved": "https://registry.npmjs.org/@dotcms/angular/-/angular-0.0.1-alpha.34.tgz", - "integrity": "sha512-YKQEPZyeLdWyDCAVJf+6O8IZtb9whtxzWjOozJPT1pkN8hrFr2xGHM670SMdhumac+/F2lrv2sIFxda9XmwUZA==", - "license": "MIT", + "version": "0.0.1-alpha.37", + "resolved": "https://registry.npmjs.org/@dotcms/angular/-/angular-0.0.1-alpha.37.tgz", + "integrity": "sha512-TyR7jWf2BqBNmmO13KmNmBYssihfWlSexZwLo7T6veJxy1cWXbld1Fs655jd/nWFs+wa1gUqLxnWYpsnSgqKKQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -2546,16 +2544,15 @@ "@angular/common": "^17.1.0", "@angular/core": "^17.1.0", "@angular/router": "^17.1.0", - "@dotcms/client": "0.0.1-alpha.34", + "@dotcms/client": "0.0.1-alpha.37", "@tinymce/tinymce-angular": "^8.0.0", "rxjs": "^7.8.0" } }, "node_modules/@dotcms/client": { - "version": "0.0.1-alpha.34", - "resolved": "https://registry.npmjs.org/@dotcms/client/-/client-0.0.1-alpha.34.tgz", - "integrity": "sha512-UsfZ+N223rQUdnuDkxwXz/Dfa5rjZ+Zg9mmFxNzLHSsnEHRLn+VjKJx586wCEJeKg7iIaNl1dHkG18gExO1fWg==", - "license": "MIT" + "version": "0.0.1-alpha.37", + "resolved": "https://registry.npmjs.org/@dotcms/client/-/client-0.0.1-alpha.37.tgz", + "integrity": "sha512-+uL6gP9sdWBC3RK5j1uESlU3+2bz8yDMoB8dF6a4kfnU5TQlCiuVFUCZRooXy8XrYhdzDxN/LiLsnLLbvoA67w==" }, "node_modules/@esbuild/aix-ppc64": { "version": "0.20.1", @@ -3877,6 +3874,7 @@ "resolved": "https://registry.npmjs.org/@tinymce/tinymce-angular/-/tinymce-angular-8.0.1.tgz", "integrity": "sha512-m0/ne5nL00YeZ7wCyhBVwKUbvS8fQZ+S+T5pinqTIqTUKpcfIC2+BIKqzUpS+niiRCowFoZl5eVlI5zdFN9/0A==", "license": "MIT", + "peer": true, "dependencies": { "tinymce": "^7.0.0 || ^6.0.0 || ^5.5.0", "tslib": "^2.3.0" @@ -12567,7 +12565,8 @@ "version": "7.3.0", "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-7.3.0.tgz", "integrity": "sha512-Ls4PgYlpk73XAxBSBqbVmSl8Mb3DuNfgF01GZ0lY6/MOEVRl3IL+VxC1Oe6165e8WqbqVsxO3Qj/PmoYNvQKGQ==", - "license": "GPL-2.0-or-later" + "license": "GPL-2.0-or-later", + "peer": true }, "node_modules/tmp": { "version": "0.0.33", diff --git a/examples/angular/src/app/app.component.ts b/examples/angular/src/app/app.component.ts index 8e8d0c3f0d2f..68bc8174f385 100644 --- a/examples/angular/src/app/app.component.ts +++ b/examples/angular/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component, inject } from '@angular/core'; +import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import { DotcmsLayoutComponent } from '@dotcms/angular'; diff --git a/examples/angular/src/app/pages/content-types/activity/activity.component.css b/examples/angular/src/app/content-types/activity/activity.component.css similarity index 100% rename from examples/angular/src/app/pages/content-types/activity/activity.component.css rename to examples/angular/src/app/content-types/activity/activity.component.css diff --git a/examples/angular/src/app/pages/content-types/activity/activity.component.ts b/examples/angular/src/app/content-types/activity/activity.component.ts similarity index 100% rename from examples/angular/src/app/pages/content-types/activity/activity.component.ts rename to examples/angular/src/app/content-types/activity/activity.component.ts diff --git a/examples/angular/src/app/pages/content-types/banner/banner.component.css b/examples/angular/src/app/content-types/banner/banner.component.css similarity index 100% rename from examples/angular/src/app/pages/content-types/banner/banner.component.css rename to examples/angular/src/app/content-types/banner/banner.component.css diff --git a/examples/angular/src/app/pages/content-types/banner/banner.component.ts b/examples/angular/src/app/content-types/banner/banner.component.ts similarity index 100% rename from examples/angular/src/app/pages/content-types/banner/banner.component.ts rename to examples/angular/src/app/content-types/banner/banner.component.ts diff --git a/examples/angular/src/app/content-types/custom-no-component/custom-no-component.component.ts b/examples/angular/src/app/content-types/custom-no-component/custom-no-component.component.ts new file mode 100644 index 000000000000..9ec23d9ce496 --- /dev/null +++ b/examples/angular/src/app/content-types/custom-no-component/custom-no-component.component.ts @@ -0,0 +1,18 @@ +import { Component, input } from '@angular/core'; +import { DotCMSContentlet } from '@dotcms/angular'; + +@Component({ + selector: 'app-custom-no-component', + standalone: true, + template: ` +
+ No component for this "{{contentlet().contentType}}" contentlet or widget +
+ `, + styles: '', +}) +export class CustomNoComponent { + contentlet = input.required(); +} diff --git a/examples/angular/src/app/pages/content-types/image/image.component.css b/examples/angular/src/app/content-types/image/image.component.css similarity index 100% rename from examples/angular/src/app/pages/content-types/image/image.component.css rename to examples/angular/src/app/content-types/image/image.component.css diff --git a/examples/angular/src/app/pages/content-types/image/image.component.ts b/examples/angular/src/app/content-types/image/image.component.ts similarity index 100% rename from examples/angular/src/app/pages/content-types/image/image.component.ts rename to examples/angular/src/app/content-types/image/image.component.ts diff --git a/examples/angular/src/app/pages/content-types/product/product.component.css b/examples/angular/src/app/content-types/product/product.component.css similarity index 100% rename from examples/angular/src/app/pages/content-types/product/product.component.css rename to examples/angular/src/app/content-types/product/product.component.css diff --git a/examples/angular/src/app/pages/content-types/product/product.component.ts b/examples/angular/src/app/content-types/product/product.component.ts similarity index 99% rename from examples/angular/src/app/pages/content-types/product/product.component.ts rename to examples/angular/src/app/content-types/product/product.component.ts index 1dc26579c1f8..f0afa97a10ff 100644 --- a/examples/angular/src/app/pages/content-types/product/product.component.ts +++ b/examples/angular/src/app/content-types/product/product.component.ts @@ -3,7 +3,6 @@ import { ChangeDetectionStrategy, Component, input, - Input, OnInit, } from '@angular/core'; diff --git a/examples/angular/src/app/pages/content-types/web-page-content/web-page-content.component.css b/examples/angular/src/app/content-types/web-page-content/web-page-content.component.css similarity index 100% rename from examples/angular/src/app/pages/content-types/web-page-content/web-page-content.component.css rename to examples/angular/src/app/content-types/web-page-content/web-page-content.component.css diff --git a/examples/angular/src/app/pages/content-types/web-page-content/web-page-content.component.ts b/examples/angular/src/app/content-types/web-page-content/web-page-content.component.ts similarity index 100% rename from examples/angular/src/app/pages/content-types/web-page-content/web-page-content.component.ts rename to examples/angular/src/app/content-types/web-page-content/web-page-content.component.ts diff --git a/examples/angular/src/app/components/blogs/blogs.component.ts b/examples/angular/src/app/pages/components/footer/blogs/blogs.component.ts similarity index 76% rename from examples/angular/src/app/components/blogs/blogs.component.ts rename to examples/angular/src/app/pages/components/footer/blogs/blogs.component.ts index 8ab4eaed84d9..36d7dcc50b3b 100644 --- a/examples/angular/src/app/components/blogs/blogs.component.ts +++ b/examples/angular/src/app/pages/components/footer/blogs/blogs.component.ts @@ -1,26 +1,23 @@ import { Component, - InjectionToken, OnInit, inject, signal, } from '@angular/core'; - -import { GenericContentlet } from '..'; -import { ContentletsComponent } from '../contentlets/contentlets.component'; import { Contentlet } from '@dotcms/client/src/lib/client/content/shared/types'; import { DotCmsClient } from '@dotcms/client'; -import { DOTCMS_CLIENT_TOKEN } from '../../app.config'; - +import { ContentletsWrapperComponent } from '../../../../shared/contentlets-wrapper/contentlets.component'; +import { DOTCMS_CLIENT_TOKEN } from '../../../../app.config'; +import { GenericContentlet } from '../..'; @Component({ selector: 'app-blogs', standalone: true, - imports: [ContentletsComponent], + imports: [ContentletsWrapperComponent], template: `

Latest Blog Posts

@if (!!blogs().length) { - + }
`, }) diff --git a/examples/angular/src/app/components/destinations/destinations.component.ts b/examples/angular/src/app/pages/components/footer/destinations/destinations.component.ts similarity index 76% rename from examples/angular/src/app/components/destinations/destinations.component.ts rename to examples/angular/src/app/pages/components/footer/destinations/destinations.component.ts index c034dc0af414..0f94af6d601e 100644 --- a/examples/angular/src/app/components/destinations/destinations.component.ts +++ b/examples/angular/src/app/pages/components/footer/destinations/destinations.component.ts @@ -1,26 +1,25 @@ import { Component, - InjectionToken, OnInit, inject, signal, } from '@angular/core'; -import { GenericContentlet } from '..'; -import { ContentletsComponent } from '../contentlets/contentlets.component'; +import { GenericContentlet } from '../..'; +import { ContentletsWrapperComponent } from '../../../../shared/contentlets-wrapper/contentlets.component'; import { Contentlet } from '@dotcms/client/src/lib/client/content/shared/types'; import { DotCmsClient } from '@dotcms/client'; -import { DOTCMS_CLIENT_TOKEN } from '../../app.config'; +import { DOTCMS_CLIENT_TOKEN } from '../../../../app.config'; @Component({ selector: 'app-destinations', standalone: true, - imports: [ContentletsComponent], + imports: [ContentletsWrapperComponent], template: `

Popular Destinations

@if (!!destinations().length) { - + }
`, }) diff --git a/examples/angular/src/app/pages/components/footer/footer.component.ts b/examples/angular/src/app/pages/components/footer/footer.component.ts index 7e6fbd8724db..264b367616eb 100644 --- a/examples/angular/src/app/pages/components/footer/footer.component.ts +++ b/examples/angular/src/app/pages/components/footer/footer.component.ts @@ -1,9 +1,10 @@ import { environment } from '../../../../environments/environment'; -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { BlogsComponent } from '../../../components/blogs/blogs.component'; -import { DestinationsComponent } from '../../../components/destinations/destinations.component'; + +import { DestinationsComponent } from './destinations/destinations.component'; import { NgOptimizedImage } from '@angular/common'; +import { BlogsComponent } from './blogs/blogs.component'; @Component({ selector: 'app-footer', diff --git a/examples/angular/src/app/components/index.ts b/examples/angular/src/app/pages/components/index.ts similarity index 58% rename from examples/angular/src/app/components/index.ts rename to examples/angular/src/app/pages/components/index.ts index 919af6e8c046..dad1bd18e77c 100644 --- a/examples/angular/src/app/components/index.ts +++ b/examples/angular/src/app/pages/components/index.ts @@ -1,23 +1,23 @@ import { DynamicComponentEntity } from '@dotcms/angular'; export const DYNAMIC_COMPONENTS: { [key: string]: DynamicComponentEntity } = { - Activity: import('../pages/content-types/activity/activity.component').then( + Activity: import('../../content-types/activity/activity.component').then( (c) => c.ActivityComponent ), - Banner: import('../pages/content-types/banner/banner.component').then( + Banner: import('../../content-types/banner/banner.component').then( (c) => c.BannerComponent ), - Image: import('../pages/content-types/image/image.component').then( + Image: import('../../content-types/image/image.component').then( (c) => c.ImageComponent ), webPageContent: import( - '../pages/content-types/web-page-content/web-page-content.component' + '../../content-types/web-page-content/web-page-content.component' ).then((c) => c.WebPageContentComponent), - Product: import('../pages/content-types/product/product.component').then( + Product: import('../../content-types/product/product.component').then( (c) => c.ProductComponent ), CustomNoComponent: import( - '../pages/content-types/custom-no-component/custom-no-component.component' + '../../content-types/custom-no-component/custom-no-component.component' ).then((c) => c.CustomNoComponent), }; diff --git a/examples/angular/src/app/pages/content-types/custom-no-component/custom-no-component.component.ts b/examples/angular/src/app/pages/content-types/custom-no-component/custom-no-component.component.ts deleted file mode 100644 index 06d858f0543e..000000000000 --- a/examples/angular/src/app/pages/content-types/custom-no-component/custom-no-component.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-custom-no-component', - standalone: true, - template: ` -
- No component for this contentlet or widget -
- `, - styles: '', -}) -export class CustomNoComponent {} diff --git a/examples/angular/src/app/pages/pages.component.ts b/examples/angular/src/app/pages/pages.component.ts index aac55435bd02..24ffc7edbf82 100644 --- a/examples/angular/src/app/pages/pages.component.ts +++ b/examples/angular/src/app/pages/pages.component.ts @@ -10,7 +10,6 @@ import { ActivatedRoute, Router } from '@angular/router'; import { NavigationEnd } from '@angular/router'; import { filter, startWith, tap } from 'rxjs/operators'; - import { DotcmsLayoutComponent, DotcmsNavigationItem, @@ -24,7 +23,7 @@ import { HeaderComponent } from './components/header/header.component'; import { NavigationComponent } from './components/navigation/navigation.component'; import { FooterComponent } from './components/footer/footer.component'; import { PageService } from './services/page.service'; -import { DYNAMIC_COMPONENTS } from '../components'; +import { DYNAMIC_COMPONENTS } from './components'; export type PageError = { message: string; diff --git a/examples/angular/src/app/components/contentlet/contentlet.component.ts b/examples/angular/src/app/shared/contentlets-wrapper/contentlet/contentlet.component.ts similarity index 75% rename from examples/angular/src/app/components/contentlet/contentlet.component.ts rename to examples/angular/src/app/shared/contentlets-wrapper/contentlet/contentlet.component.ts index cd7a80cbd042..db5e3c1c96c1 100644 --- a/examples/angular/src/app/components/contentlet/contentlet.component.ts +++ b/examples/angular/src/app/shared/contentlets-wrapper/contentlet/contentlet.component.ts @@ -1,10 +1,16 @@ -import { Component, input, Input } from '@angular/core'; +import { Component, input } from '@angular/core'; -import { GenericContentlet } from '..'; import { Contentlet } from '@dotcms/client/src/lib/client/content/shared/types'; import { isInsideEditor } from '@dotcms/client'; import { NgTemplateOutlet } from '@angular/common'; +import { GenericContentlet } from '../../../pages/components'; +/** + * Local component for rendering a single contentlet outside the DotCmsLayout. + * This is useful when you want to render a contentlet in a different context than the DotCmsLayout, like in a modal, sidebar, footer, etc. + * @export + * @class ContentletComponent + */ @Component({ selector: 'app-contentlet', standalone: true, diff --git a/examples/angular/src/app/components/contentlets/contentlets.component.ts b/examples/angular/src/app/shared/contentlets-wrapper/contentlets.component.ts similarity index 79% rename from examples/angular/src/app/components/contentlets/contentlets.component.ts rename to examples/angular/src/app/shared/contentlets-wrapper/contentlets.component.ts index 88e5acaed91d..b92423ebfb22 100644 --- a/examples/angular/src/app/components/contentlets/contentlets.component.ts +++ b/examples/angular/src/app/shared/contentlets-wrapper/contentlets.component.ts @@ -1,11 +1,18 @@ import { Component, input } from '@angular/core'; import { Contentlet } from '@dotcms/client/src/lib/client/content/shared/types'; -import { GenericContentlet } from '..'; +import { GenericContentlet } from '../../pages/components'; import { DatePipe, NgOptimizedImage } from '@angular/common'; -import { ContentletComponent } from '../contentlet/contentlet.component'; +import { ContentletComponent } from './contentlet/contentlet.component'; + +/** + * Local component for rendering a list of contentlets outside the DotCmsLayout. + * + * @export + * @class ContentletsComponent + */ @Component({ - selector: 'app-contentlets', + selector: 'app-contentlets-wrapper', standalone: true, imports: [NgOptimizedImage, DatePipe, ContentletComponent], template: `
    @@ -40,12 +47,6 @@ import { ContentletComponent } from '../contentlet/contentlet.component'; }
`, }) -export class ContentletsComponent { +export class ContentletsWrapperComponent { contentlets = input.required[]>(); - - dateFormatOptions: Intl.DateTimeFormatOptions = { - year: 'numeric', - month: 'long', - day: 'numeric', - }; }