diff --git a/docs/src/components/Announcement.astro b/docs/src/components/Announcement.astro index 6290176..8541a64 100644 --- a/docs/src/components/Announcement.astro +++ b/docs/src/components/Announcement.astro @@ -2,8 +2,8 @@ --- - - New textarea component + + New pagination component + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ng@latest add pagination +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + UbPaginationContentDirective, + UbPaginationDirective, + UbPaginationEllipsisComponent, + UbPaginationItemDirective, + UbPaginationLinkDirective, + UbPaginationNextDirective, + UbPaginationPreviousDirective, +} from "@/components/ui/pagination" +``` + +```html + +``` diff --git a/docs/src/registry/default/example/pagination-demo.ts b/docs/src/registry/default/example/pagination-demo.ts new file mode 100644 index 0000000..aed29ea --- /dev/null +++ b/docs/src/registry/default/example/pagination-demo.ts @@ -0,0 +1,50 @@ +import { + UbPaginationContentDirective, + UbPaginationDirective, + UbPaginationEllipsisComponent, + UbPaginationItemDirective, + UbPaginationLinkDirective, + UbPaginationNextDirective, + UbPaginationPreviousDirective, +} from '@/registry/default/ui/pagination' + +import { Component } from '@angular/core' + +@Component({ + standalone: true, + selector: '[pagination-demo-default]', + imports: [ + UbPaginationContentDirective, + UbPaginationDirective, + UbPaginationEllipsisComponent, + UbPaginationItemDirective, + UbPaginationLinkDirective, + UbPaginationNextDirective, + UbPaginationPreviousDirective, + ], + template: ` + + `, +}) +export default class PaginationDemoDefault { } diff --git a/docs/src/registry/default/ui/pagination.ts b/docs/src/registry/default/ui/pagination.ts new file mode 100644 index 0000000..77aab88 --- /dev/null +++ b/docs/src/registry/default/ui/pagination.ts @@ -0,0 +1,136 @@ +import { cn } from '@/lib/utils' +import { buttonVariants, type UbButtonSize } from '@/registry/default/ui/button' +import { booleanAttribute, Component, computed, Directive, effect, inject, input } from '@angular/core' +import { NgIcon, provideIcons } from '@ng-icons/core' +import { lucideChevronLeft, lucideChevronRight, lucideEllipsis } from '@ng-icons/lucide' + +@Directive({ + standalone: true, + selector: 'nav[ubPagination]', + host: { + 'role': 'navigation', + 'aria-label': 'pagination', + '[class]': 'computedClass()', + }, +}) +export class UbPaginationDirective { + class = input() + computedClass = computed(() => cn('mx-auto flex w-full justify-center', this.class())) +} + +@Directive({ + standalone: true, + selector: 'ul[ubPaginationContent]', + host: { + '[class]': 'computedClass()', + }, +}) +export class UbPaginationContentDirective { + class = input() + computedClass = computed(() => cn('flex flex-row items-center gap-1', this.class())) +} + +@Directive({ + standalone: true, + selector: 'li[ubPaginationItem]', + host: { + '[class]': 'computedClass()', + }, +}) +export class UbPaginationItemDirective { + class = input() + computedClass = computed(() => cn('', this.class())) +} + +@Directive({ + standalone: true, + selector: '[ubPaginationLink]', + host: { + '[aria-current]': 'isActive() ? "page" : undefined', + '[class]': 'computedClass()', + }, +}) +export class UbPaginationLinkDirective { + class = input() + isActive = input(false, { transform: booleanAttribute }) + size = input('icon') + computedClass = computed(() => cn( + buttonVariants({ + variant: this.isActive() ? 'outline' : 'ghost', + size: this.size(), + }), + this.class(), + )) +} + +@Component({ + standalone: true, + selector: '[ubPaginationPrevious]', + imports: [NgIcon], + hostDirectives: [UbPaginationLinkDirective], + host: { + '[class]': 'computedClass()', + 'aria-label': 'Go to previous page', + }, + providers: [provideIcons({ lucideChevronLeft })], + template: ` + + Previous + `, +}) +export class UbPaginationPreviousDirective { + class = input() + computedClass = computed(() => cn('gap-1 pl-2.5', this.class())) + protected size = input('default') + private ubPaginationLinkDirective = inject(UbPaginationLinkDirective, { host: true }) + + setConfig = effect(() => { + this.ubPaginationLinkDirective.size = this.size + }) +} + +@Component({ + standalone: true, + selector: '[ubPaginationNext]', + imports: [NgIcon], + providers: [provideIcons({ lucideChevronRight })], + hostDirectives: [UbPaginationLinkDirective], + host: { + '[class]': 'computedClass()', + 'aria-label': 'Go to next page', + }, + template: ` + Next + + `, +}) +export class UbPaginationNextDirective { + class = input() + computedClass = computed(() => cn('gap-1 pr-2.5', this.class())) + protected size = input('default') + private ubPaginationLinkDirective = inject(UbPaginationLinkDirective, { host: true }) + + setConfig = effect(() => { + this.ubPaginationLinkDirective.size = this.size + }) +} + +@Component({ + standalone: true, + imports: [NgIcon], + providers: [provideIcons({ lucideEllipsis })], + selector: 'ub-pagination-ellipsis', + template: ` + + `, +}) +export class UbPaginationEllipsisComponent { + class = input() + computedClass = computed(() => cn('flex h-9 w-9 items-center justify-center', this.class())) +} diff --git a/docs/src/registry/new-york/example/pagination-demo.ts b/docs/src/registry/new-york/example/pagination-demo.ts new file mode 100644 index 0000000..a284784 --- /dev/null +++ b/docs/src/registry/new-york/example/pagination-demo.ts @@ -0,0 +1,50 @@ +import { + UbPaginationContentDirective, + UbPaginationDirective, + UbPaginationEllipsisComponent, + UbPaginationItemDirective, + UbPaginationLinkDirective, + UbPaginationNextDirective, + UbPaginationPreviousDirective, +} from '@/registry/new-york/ui/pagination' + +import { Component } from '@angular/core' + +@Component({ + standalone: true, + selector: '[pagination-demo-new-york]', + imports: [ + UbPaginationContentDirective, + UbPaginationDirective, + UbPaginationEllipsisComponent, + UbPaginationItemDirective, + UbPaginationLinkDirective, + UbPaginationNextDirective, + UbPaginationPreviousDirective, + ], + template: ` + + `, +}) +export default class PaginationDemoNewYork { } diff --git a/docs/src/registry/new-york/ui/button.ts b/docs/src/registry/new-york/ui/button.ts index 4c51fc8..4c6de81 100644 --- a/docs/src/registry/new-york/ui/button.ts +++ b/docs/src/registry/new-york/ui/button.ts @@ -36,8 +36,8 @@ export const buttonVariants = cva( type ButtonProps = VariantProps -export type ButtonSize = NonNullable -export type ButtonVariant = NonNullable +export type UbButtonSize = NonNullable +export type UbButtonVariant = NonNullable @Directive({ selector: '[ubButton]', @@ -49,9 +49,9 @@ export type ButtonVariant = NonNullable export class UbButtonDirective { readonly class = input() - readonly variant = input('default') + readonly variant = input('default') - readonly size = input('default') + readonly size = input('default') protected computedClass = computed(() => cn( diff --git a/docs/src/registry/new-york/ui/pagination.ts b/docs/src/registry/new-york/ui/pagination.ts new file mode 100644 index 0000000..82ffa02 --- /dev/null +++ b/docs/src/registry/new-york/ui/pagination.ts @@ -0,0 +1,136 @@ +import { cn } from '@/lib/utils' +import { buttonVariants, type UbButtonSize } from '@/registry/new-york/ui/button' +import { booleanAttribute, Component, computed, Directive, effect, inject, input } from '@angular/core' +import { NgIcon, provideIcons } from '@ng-icons/core' +import { lucideChevronLeft, lucideChevronRight, lucideEllipsis } from '@ng-icons/lucide' + +@Directive({ + standalone: true, + selector: 'nav[ubPagination]', + host: { + 'role': 'navigation', + 'aria-label': 'pagination', + '[class]': 'computedClass()', + }, +}) +export class UbPaginationDirective { + class = input() + computedClass = computed(() => cn('mx-auto flex w-full justify-center', this.class())) +} + +@Directive({ + standalone: true, + selector: 'ul[ubPaginationContent]', + host: { + '[class]': 'computedClass()', + }, +}) +export class UbPaginationContentDirective { + class = input() + computedClass = computed(() => cn('flex flex-row items-center gap-1', this.class())) +} + +@Directive({ + standalone: true, + selector: 'li[ubPaginationItem]', + host: { + '[class]': 'computedClass()', + }, +}) +export class UbPaginationItemDirective { + class = input() + computedClass = computed(() => cn('', this.class())) +} + +@Directive({ + standalone: true, + selector: '[ubPaginationLink]', + host: { + '[aria-current]': 'isActive() ? "page" : undefined', + '[class]': 'computedClass()', + }, +}) +export class UbPaginationLinkDirective { + class = input() + isActive = input(false, { transform: booleanAttribute }) + size = input('icon') + computedClass = computed(() => cn( + buttonVariants({ + variant: this.isActive() ? 'outline' : 'ghost', + size: this.size(), + }), + this.class(), + )) +} + +@Component({ + standalone: true, + selector: '[ubPaginationPrevious]', + imports: [NgIcon], + hostDirectives: [UbPaginationLinkDirective], + host: { + '[class]': 'computedClass()', + 'aria-label': 'Go to previous page', + }, + providers: [provideIcons({ lucideChevronLeft })], + template: ` + + Previous + `, +}) +export class UbPaginationPreviousDirective { + class = input() + computedClass = computed(() => cn('gap-1 pl-2.5', this.class())) + protected size = input('default') + private ubPaginationLinkDirective = inject(UbPaginationLinkDirective, { host: true }) + + setConfig = effect(() => { + this.ubPaginationLinkDirective.size = this.size + }) +} + +@Component({ + standalone: true, + selector: '[ubPaginationNext]', + imports: [NgIcon], + providers: [provideIcons({ lucideChevronRight })], + hostDirectives: [UbPaginationLinkDirective], + host: { + '[class]': 'computedClass()', + 'aria-label': 'Go to next page', + }, + template: ` + Next + + `, +}) +export class UbPaginationNextDirective { + class = input() + computedClass = computed(() => cn('gap-1 pr-2.5', this.class())) + protected size = input('default') + private ubPaginationLinkDirective = inject(UbPaginationLinkDirective, { host: true }) + + setConfig = effect(() => { + this.ubPaginationLinkDirective.size = this.size + }) +} + +@Component({ + standalone: true, + imports: [NgIcon], + providers: [provideIcons({ lucideEllipsis })], + selector: 'ub-pagination-ellipsis', + template: ` + + `, +}) +export class UbPaginationEllipsisComponent { + class = input() + computedClass = computed(() => cn('flex h-9 w-9 items-center justify-center', this.class())) +} diff --git a/docs/src/registry/registry-examples.ts b/docs/src/registry/registry-examples.ts index 2b4a22b..8ee54f2 100644 --- a/docs/src/registry/registry-examples.ts +++ b/docs/src/registry/registry-examples.ts @@ -151,6 +151,12 @@ export const examples: Registry = [ registryDependencies: ['input'], files: ['example/input-file.ts'], }, + { + name: 'pagination-demo', + type: 'registry:example', + registryDependencies: ['pagination'], + files: ['example/pagination-demo.ts'], + }, { name: 'progress-demo', type: 'registry:example', diff --git a/docs/src/registry/registry-ui.ts b/docs/src/registry/registry-ui.ts index 498f87b..7c243a7 100644 --- a/docs/src/registry/registry-ui.ts +++ b/docs/src/registry/registry-ui.ts @@ -89,6 +89,11 @@ export const ui: Registry = [ dependencies: ['@radix-ng/primitives'], files: [{ path: 'ui/label.ts', type: 'registry:ui' }], }, + { + name: 'pagination', + type: 'registry:ui', + files: [{ path: 'ui/pagination.ts', type: 'registry:ui' }], + }, { name: 'progress', type: 'registry:ui',