@goat-bravos/intern-hub-layout 1.0.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/.editorconfig +17 -0
  2. package/.vscode/extensions.json +4 -0
  3. package/.vscode/launch.json +20 -0
  4. package/.vscode/mcp.json +9 -0
  5. package/.vscode/tasks.json +42 -0
  6. package/README.md +797 -185
  7. package/angular.json +40 -0
  8. package/ng-package.json +11 -0
  9. package/package.json +24 -16
  10. package/src/libs/layouts/header/header.component.html +58 -0
  11. package/src/libs/layouts/header/header.component.scss +108 -0
  12. package/src/libs/layouts/header/header.component.ts +70 -0
  13. package/src/libs/layouts/sidebar/sidebar.component.html +28 -0
  14. package/src/libs/layouts/sidebar/sidebar.component.scss +44 -0
  15. package/src/libs/layouts/sidebar/sidebar.component.ts +55 -0
  16. package/src/libs/shared/components/approval/approval-list/approval-list.component.html +19 -0
  17. package/src/libs/shared/components/approval/approval-list/approval-list.component.scss +24 -0
  18. package/src/libs/shared/components/approval/approval-list/approval-list.component.ts +19 -0
  19. package/src/libs/shared/components/approval/approval-list-item/approval-list-item.component.html +21 -0
  20. package/src/libs/shared/components/approval/approval-list-item/approval-list-item.component.scss +28 -0
  21. package/src/libs/shared/components/approval/approval-list-item/approval-list-item.component.ts +20 -0
  22. package/src/libs/shared/components/approval/approval-list-item/approval-list-item.model.ts +8 -0
  23. package/src/libs/shared/components/button/button-container/button-container.component.html +20 -0
  24. package/src/libs/shared/components/button/button-container/button-container.component.scss +49 -0
  25. package/src/libs/shared/components/button/button-container/button-container.component.ts +34 -0
  26. package/src/libs/shared/components/button/button-container/button-container.model.ts +58 -0
  27. package/src/libs/shared/components/button/label-button/label-button.component.html +11 -0
  28. package/src/libs/shared/components/button/label-button/label-button.component.scss +13 -0
  29. package/src/libs/shared/components/button/label-button/label-button.component.ts +18 -0
  30. package/src/libs/shared/components/functional-label/functional-label.component.html +36 -0
  31. package/src/libs/shared/components/functional-label/functional-label.component.scss +56 -0
  32. package/src/libs/shared/components/functional-label/functional-label.component.ts +141 -0
  33. package/src/libs/shared/components/icon/icon.component.html +12 -0
  34. package/src/libs/shared/components/icon/icon.component.scss +11 -0
  35. package/src/libs/shared/components/icon/icon.component.ts +61 -0
  36. package/src/libs/shared/components/input/input-calendar/input-calendar.component.html +52 -0
  37. package/src/libs/shared/components/input/input-calendar/input-calendar.component.scss +98 -0
  38. package/src/libs/shared/components/input/input-calendar/input-calendar.component.ts +126 -0
  39. package/src/libs/shared/components/input/input-label/input-label.component.html +0 -0
  40. package/src/libs/shared/components/input/input-label/input-label.component.scss +0 -0
  41. package/src/libs/shared/components/input/input-label/input-label.component.ts +0 -0
  42. package/src/libs/shared/components/input/input-stepper/input-stepper.component.html +62 -0
  43. package/src/libs/shared/components/input/input-stepper/input-stepper.component.scss +211 -0
  44. package/src/libs/shared/components/input/input-stepper/input-stepper.component.ts +73 -0
  45. package/src/libs/shared/components/input/input-text/input-text.component.html +40 -0
  46. package/src/libs/shared/components/input/input-text/input-text.component.scss +143 -0
  47. package/src/libs/shared/components/input/input-text/input-text.component.ts +63 -0
  48. package/src/libs/shared/components/pop-up/pop-up-confirm/pop-up-confirm.component.html +15 -0
  49. package/src/libs/shared/components/pop-up/pop-up-confirm/pop-up-confirm.component.scss +70 -0
  50. package/src/libs/shared/components/pop-up/pop-up-confirm/pop-up-confirm.component.ts +29 -0
  51. package/src/libs/shared/components/table/table-body/table-body.component.html +18 -0
  52. package/src/libs/shared/components/table/table-body/table-body.component.scss +6 -0
  53. package/src/libs/shared/components/table/table-body/table-body.component.ts +17 -0
  54. package/src/libs/shared/components/table/table-header/table-header.component.html +27 -0
  55. package/src/libs/shared/components/table/table-header/table-header.component.scss +91 -0
  56. package/src/libs/shared/components/table/table-header/table-header.component.ts +25 -0
  57. package/src/public-api.ts +34 -0
  58. package/tsconfig.json +38 -0
  59. package/tsconfig.lib.json +17 -0
  60. package/tsconfig.lib.prod.json +11 -0
  61. package/tsconfig.spec.json +15 -0
  62. package/fesm2022/goat-bravos-intern-hub-layout.mjs +0 -561
  63. package/fesm2022/goat-bravos-intern-hub-layout.mjs.map +0 -1
  64. package/types/goat-bravos-intern-hub-layout.d.ts +0 -189
package/README.md CHANGED
@@ -1,267 +1,879 @@
1
- # Intern Hub Layout
1
+ # 🏢 Intern Hub Layout
2
2
 
3
- This library provides a standard layout and shared UI components for Intern Hub applications. It is designed to be highly configurable via Angular Routing.
3
+ ![Angular](https://img.shields.io/badge/Angular-21-DD0031?style=flat&logo=angular&logoColor=white)
4
+ ![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?style=flat&logo=typescript&logoColor=white)
5
+ ![License](https://img.shields.io/badge/License-MIT-green?style=flat)
6
+ ![npm](https://img.shields.io/badge/npm-@goat--bravos/intern--hub--layout-CB3837?style=flat&logo=npm)
4
7
 
5
- ## Installation
8
+ A comprehensive Angular library providing reusable layout components and shared UI elements for Intern Hub applications. Built with Angular 21 and designed for seamless integration.
6
9
 
7
- Run the following command to install the package:
10
+ ---
11
+
12
+ ## 📋 Table of Contents
13
+
14
+ - [Features](#-features)
15
+ - [Installation](#-installation)
16
+ - [Quick Start](#-quick-start)
17
+ - [Components](#-components)
18
+ - [Layout Components](#layout-components)
19
+ - [Button Components](#button-components)
20
+ - [Input Components](#input-components)
21
+ - [Table Components](#table-components)
22
+ - [Approval Components](#approval-components)
23
+ - [Pop-up Components](#pop-up-components)
24
+ - [Icon Components](#icon-components)
25
+ - [Development](#-development)
26
+ - [Contributing](#-contributing)
27
+ - [License](#-license)
28
+
29
+ ---
30
+
31
+ ## ✨ Features
32
+
33
+ - 🎨 **Pre-built Layouts** - Header and sidebar components with hover effects
34
+ - 🧩 **Reusable UI Components** - Buttons, inputs, tables, approval lists, and more
35
+ - 🔧 **Highly Configurable** - Extensive customization via inputs
36
+ - 📦 **Standalone Components** - Modern Angular standalone component architecture
37
+ - 🎯 **TypeScript Support** - Full type definitions included
38
+ - ♿ **Accessible** - Built with accessibility best practices
39
+ - 🚀 **Angular 21 Ready** - Built for the latest Angular version
40
+
41
+ ---
42
+
43
+ ## 📦 Installation
44
+
45
+ Install the package via npm:
8
46
 
9
47
  ```bash
10
- npm install intern-hub-layout dynamic-ds
48
+ npm install @goat-bravos/intern-hub-layout
11
49
  ```
12
50
 
13
- _(Note: `dynamic-ds` is a required peer dependency for the design system)_
51
+ ### Peer Dependencies
52
+
53
+ This library requires the following peer dependencies:
54
+
55
+ | Package | Version | Required |
56
+ | ----------------- | ------- | ----------- |
57
+ | `@angular/common` | ^21.0.0 | ✅ Yes |
58
+ | `@angular/core` | ^21.0.0 | ✅ Yes |
59
+ | `@angular/forms` | ^21.0.0 | ✅ Yes |
60
+ | `@angular/router` | ^21.0.0 | ✅ Yes |
61
+ | `dynamic-ds` | ^1.0.2 | ⚠️ Optional |
62
+
63
+ Install peer dependencies if not already present:
14
64
 
15
- ## Setup
65
+ ```bash
66
+ npm install @angular/common @angular/core @angular/forms @angular/router
67
+ ```
68
+
69
+ ---
16
70
 
17
- To enable the configurable layout pattern, you must add `withComponentInputBinding()` to your `app.config.ts`. This allows the Router to pass configuration data directly to the Layout component inputs.
71
+ ## 🚀 Quick Start
18
72
 
19
- **`src/app/app.config.ts`**
73
+ ### Step 1: Import Components
74
+
75
+ Import the components you need in your Angular component:
20
76
 
21
77
  ```typescript
22
- import { ApplicationConfig } from '@angular/core';
23
- import { provideRouter, withComponentInputBinding } from '@angular/router'; // Import this
24
- import { routes } from './app.routes';
25
-
26
- export const appConfig: ApplicationConfig = {
27
- providers: [
28
- provideRouter(routes, withComponentInputBinding()), // Add this function
29
- ],
30
- };
78
+ import { Component } from "@angular/core";
79
+ import { HeaderComponent, SidebarComponent, ButtonContainerComponent, InputTextComponent } from "@goat-bravos/intern-hub-layout";
80
+
81
+ @Component({
82
+ selector: "app-root",
83
+ standalone: true,
84
+ imports: [HeaderComponent, SidebarComponent, ButtonContainerComponent, InputTextComponent],
85
+ templateUrl: "./app.component.html",
86
+ })
87
+ export class AppComponent {}
88
+ ```
89
+
90
+ ### Step 2: Use in Template
91
+
92
+ ```html
93
+ <!-- Header -->
94
+ <app-header-component [data]="headerData"></app-header-component>
95
+
96
+ <!-- Sidebar -->
97
+ <app-sidebar [data]="sidebarData"></app-sidebar>
98
+
99
+ <!-- Button -->
100
+ <app-button-container content="Click Me" size="md" backgroundColor="var(--brand-500)" (buttonClick)="onButtonClick()"></app-button-container>
101
+
102
+ <!-- Input -->
103
+ <app-input-text headerInput="Username" placeholder="Enter your username" [required]="true" [(value)]="username"></app-input-text>
31
104
  ```
32
105
 
33
- ## Usage
106
+ ---
107
+
108
+ ## 🧩 Components
109
+
110
+ ### Layout Components
34
111
 
35
- ### 1. Main Layout Configuration
112
+ #### HeaderComponent
36
113
 
37
- You can use the `MainLayoutComponent` as a shell for your application. Define the Sidebar items directly in your route configuration using the `data` property.
114
+ A responsive header with logo, action buttons, and user profile.
38
115
 
39
- **`src/app/app.routes.ts`**
116
+ **Selector:** `app-header-component`
40
117
 
41
118
  ```typescript
42
- import { Routes } from '@angular/router';
43
- import { MainLayoutComponent } from 'intern-hub-layout'; // Import from library
44
-
45
- export const routes: Routes = [
46
- {
47
- path: '',
48
- component: MainLayoutComponent,
49
- // Configure Sidebar Items here
50
- data: {
51
- sidebarItems: [
52
- { icon: 'dsi-home-01-line', content: 'Home' },
53
- { icon: 'dsi-map-01-line', content: 'Roadmap' },
54
- { icon: 'dsi-file-01-line', content: 'Documents' },
55
- ],
56
- },
57
- // Your application pages go here
58
- children: [
119
+ import { HeaderComponent, HeaderData } from "@goat-bravos/intern-hub-layout";
120
+
121
+ @Component({
122
+ imports: [HeaderComponent],
123
+ template: `<app-header-component [data]="headerData"></app-header-component>`,
124
+ })
125
+ export class MyComponent {
126
+ headerData: HeaderData = {
127
+ headerItems: [
128
+ {
129
+ icon: "dsi-bell-line",
130
+ content: "Notifications",
131
+ badge: "5",
132
+ method: () => console.log("Notifications clicked"),
133
+ },
59
134
  {
60
- path: '',
61
- loadComponent: () => import('./home/home.component').then((m) => m.HomeComponent),
135
+ icon: "dsi-settings-line",
136
+ content: "Settings",
137
+ method: () => console.log("Settings clicked"),
62
138
  },
63
139
  ],
64
- },
65
- ];
140
+ userName: "John Doe",
141
+ userIcon: "dsi-user-01-line",
142
+ dropdownIcon: "dsi-arrow-down-solid",
143
+ logo: "assets/logo.png",
144
+ };
145
+ }
146
+ ```
147
+
148
+ **Interfaces:**
149
+
150
+ ```typescript
151
+ interface HeaderData {
152
+ headerItems: HeaderAction[];
153
+ userName: string;
154
+ userIcon?: IconData | string;
155
+ userIconColor?: string;
156
+ dropdownIcon?: IconData | string;
157
+ dropdownIconColor?: string;
158
+ logo?: string;
159
+ }
160
+
161
+ interface HeaderAction {
162
+ icon: IconData | string;
163
+ content: string;
164
+ method?: () => void;
165
+ badge?: string;
166
+ colorIcon?: string;
167
+ width?: string;
168
+ height?: string;
169
+ }
66
170
  ```
67
171
 
68
- ### 2. Using Shared Components
172
+ ---
173
+
174
+ #### SidebarComponent
69
175
 
70
- You can import individual components from the library.
176
+ A collapsible sidebar with hover expansion and customizable menu items.
177
+
178
+ **Selector:** `app-sidebar`
71
179
 
72
180
  ```typescript
73
- import { Component } from '@angular/core';
74
- import { ButtonContainerComponent, InputTextComponent } from 'intern-hub-layout';
181
+ import { SidebarComponent, SidebarData, SidebarItem } from "@goat-bravos/intern-hub-layout";
75
182
 
76
183
  @Component({
77
- selector: 'app-example',
78
- standalone: true,
79
- imports: [ButtonContainerComponent, InputTextComponent],
184
+ imports: [SidebarComponent],
185
+ template: `<app-sidebar [data]="sidebarData"></app-sidebar>`,
186
+ })
187
+ export class MyComponent {
188
+ sidebarData: SidebarData = {
189
+ menuItems: [
190
+ {
191
+ iconLeft: "dsi-home-01-line",
192
+ content: "Dashboard",
193
+ url: "/dashboard",
194
+ colorIconLeft: "#666",
195
+ colorIconLeftHover: "#fff",
196
+ backgroundColor: "transparent",
197
+ backgroundColorHover: "#3b82f6",
198
+ },
199
+ {
200
+ iconLeft: "dsi-users-line",
201
+ content: "Users",
202
+ url: "/users",
203
+ colorIconLeft: "#666",
204
+ colorIconLeftHover: "#fff",
205
+ },
206
+ {
207
+ iconLeft: "dsi-settings-line",
208
+ content: "Settings",
209
+ url: "/settings",
210
+ },
211
+ ],
212
+ backgroundColor: "#1e293b",
213
+ };
214
+ }
215
+ ```
216
+
217
+ **Interface:**
218
+
219
+ ```typescript
220
+ interface SidebarItem {
221
+ iconLeft?: IconData | string;
222
+ iconRight?: IconData | string;
223
+ content: string;
224
+ url?: string;
225
+ colorIconLeft?: string;
226
+ colorIconLeftHover?: string;
227
+ colorIconRight?: string;
228
+ colorIconRightHover?: string;
229
+ colorContent?: string;
230
+ colorContentHover?: string;
231
+ backgroundColor?: string;
232
+ backgroundColorHover?: string;
233
+ borderRadius?: string;
234
+ borderRadiusHover?: string;
235
+ width?: string;
236
+ height?: string;
237
+ }
238
+
239
+ interface SidebarData {
240
+ menuItems: SidebarItem[];
241
+ backgroundColor?: string;
242
+ }
243
+ ```
244
+
245
+ ---
246
+
247
+ ### Button Components
248
+
249
+ #### ButtonContainerComponent
250
+
251
+ A customizable button with icon support and multiple size variants.
252
+
253
+ **Selector:** `app-button-container`
254
+
255
+ ```typescript
256
+ import { ButtonContainerComponent, ButtonSize } from "@goat-bravos/intern-hub-layout";
257
+
258
+ @Component({
259
+ imports: [ButtonContainerComponent],
80
260
  template: `
81
- <app-button-container content="Click Me"></app-button-container>
82
- <app-input-text placeholder="Enter name"></app-input-text>
261
+ <!-- Basic button -->
262
+ <app-button-container content="Submit" size="md" (buttonClick)="onSubmit()"></app-button-container>
263
+
264
+ <!-- Button with icons -->
265
+ <app-button-container content="Download" size="lg" leftIcon="⬇" backgroundColor="#10b981" color="#ffffff" (buttonClick)="onDownload()"></app-button-container>
266
+
267
+ <!-- Small button -->
268
+ <app-button-container content="Edit" size="xs" backgroundColor="#f59e0b" (buttonClick)="onEdit()"></app-button-container>
83
269
  `,
84
270
  })
85
- export class ExampleComponent {}
271
+ export class MyComponent {
272
+ onSubmit() {
273
+ console.log("Form submitted");
274
+ }
275
+ onDownload() {
276
+ console.log("Download initiated");
277
+ }
278
+ onEdit() {
279
+ console.log("Edit clicked");
280
+ }
281
+ }
86
282
  ```
87
283
 
88
- ## Available Components
284
+ **Inputs:**
89
285
 
90
- ### Layouts
286
+ | Input | Type | Default | Description |
287
+ | ----------------- | ------------------------------ | ---------------------- | --------------------- |
288
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | `'md'` | Button size variant |
289
+ | `content` | `string` | `''` | Button text |
290
+ | `leftIcon` | `string` | - | Left icon text/class |
291
+ | `rightIcon` | `string` | - | Right icon text/class |
292
+ | `color` | `string` | `'var(--brand-100)'` | Text color |
293
+ | `backgroundColor` | `string` | `'var(--utility-900)'` | Background color |
294
+ | `borderColor` | `string` | `'var(--brand-100)'` | Border color |
295
+ | `fontSize` | `string` | - | Custom font size |
91
296
 
92
- - `MainLayoutComponent`: Full application shell with Sidebar and Header.
93
- - `SidebarComponent`: Standalone sidebar.
94
- - `HeaderComponent`: Standalone header.
297
+ **Outputs:**
95
298
 
96
- ### Shared UI
299
+ | Output | Type | Description |
300
+ | ------------- | ------------------- | ------------------------- |
301
+ | `buttonClick` | `EventEmitter<any>` | Emits when button clicked |
97
302
 
98
- - **Buttons**: `ButtonContainerComponent`, `LabelButtonComponent`
99
- - **Inputs**: `InputTextComponent`, `InputStepperComponent`, `InputCalendarComponent`
100
- - **Tables**: `TableHeaderComponent`, `TableBodyComponent`
101
- - **Other**: `ApprovalListComponent`, `PopUpConfirmComponent`
303
+ ---
102
304
 
103
- ## Author
305
+ #### LabelButtonComponent
104
306
 
105
- Intern Hub Team
307
+ A simple label/badge style button for status indicators.
106
308
 
107
- ## Component API Reference
309
+ **Selector:** `app-label-button`
108
310
 
109
- ### 1. `MainLayoutComponent`
311
+ ```typescript
312
+ import { LabelButtonComponent } from "@goat-bravos/intern-hub-layout";
313
+
314
+ @Component({
315
+ imports: [LabelButtonComponent],
316
+ template: `
317
+ <!-- Success status -->
318
+ <app-label-button label="Active" bgColor="#22c55e" textColor="#ffffff"></app-label-button>
319
+
320
+ <!-- Warning status -->
321
+ <app-label-button label="Pending" bgColor="#f59e0b" textColor="#000000"></app-label-button>
322
+
323
+ <!-- Custom size -->
324
+ <app-label-button label="Custom" bgColor="#3b82f6" width="120px" height="32px"></app-label-button>
325
+ `,
326
+ })
327
+ export class MyComponent {}
328
+ ```
329
+
330
+ **Inputs:**
331
+
332
+ | Input | Type | Default | Description |
333
+ | ------------- | -------- | ---------------------- | ---------------- |
334
+ | `label` | `string` | `''` | Button text |
335
+ | `bgColor` | `string` | `''` | Background color |
336
+ | `borderColor` | `string` | `''` | Border color |
337
+ | `textColor` | `string` | `'var(--neutral-100)'` | Text color |
338
+ | `width` | `string` | `'100%'` | Button width |
339
+ | `height` | `string` | `'28px'` | Button height |
340
+
341
+ ---
342
+
343
+ ### Input Components
110
344
 
111
- The main application shell.
345
+ #### InputTextComponent
112
346
 
113
- - **Inputs**:
114
- - `sidebarItems: SidebarItem[]`: List of items to display in the sidebar.
347
+ A text input with label, character limit, and icon support.
115
348
 
116
- #### Interface `SidebarItem`
349
+ **Selector:** `app-input-text`
117
350
 
118
351
  ```typescript
119
- interface SidebarItem {
120
- icon: string;
121
- content: string;
352
+ import { InputTextComponent } from "@goat-bravos/intern-hub-layout";
353
+
354
+ @Component({
355
+ imports: [InputTextComponent],
356
+ template: `
357
+ <!-- Basic input -->
358
+ <app-input-text headerInput="Email" placeholder="Enter your email" [required]="true" [(value)]="email" (valueChange)="onEmailChange($event)"></app-input-text>
359
+
360
+ <!-- Input with character limit -->
361
+ <app-input-text headerInput="Bio" placeholder="Tell us about yourself" [maxLength]="200" [showLimit]="true" [(value)]="bio"></app-input-text>
362
+
363
+ <!-- Password input with icon -->
364
+ <app-input-text headerInput="Password" placeholder="Enter password" typeInput="password" icon="dsi-eye-line" (iconClick)="togglePassword()" [(value)]="password"></app-input-text>
365
+ `,
366
+ })
367
+ export class MyComponent {
368
+ email = "";
369
+ bio = "";
370
+ password = "";
371
+
372
+ onEmailChange(value: string) {
373
+ console.log("Email changed:", value);
374
+ }
375
+
376
+ togglePassword() {
377
+ // Toggle password visibility
378
+ }
122
379
  }
123
380
  ```
124
381
 
382
+ **Inputs:**
383
+
384
+ | Input | Type | Default | Description |
385
+ | ------------- | --------- | -------- | ------------------------------ |
386
+ | `headerInput` | `string` | `''` | Label text above input |
387
+ | `placeholder` | `string` | `''` | Placeholder text |
388
+ | `value` | `string` | `''` | Input value (two-way binding) |
389
+ | `readonly` | `boolean` | `false` | Read-only state |
390
+ | `required` | `boolean` | `false` | Shows required indicator (\*) |
391
+ | `width` | `string` | `'100%'` | Container width |
392
+ | `maxLength` | `number` | `0` | Max characters (0 = unlimited) |
393
+ | `showLimit` | `boolean` | `false` | Show character count |
394
+ | `icon` | `string` | `''` | Icon class for input |
395
+ | `typeInput` | `string` | `'text'` | Input type |
396
+
397
+ **Outputs:**
398
+
399
+ | Output | Type | Description |
400
+ | ------------- | ---------------------- | -------------------------- |
401
+ | `valueChange` | `EventEmitter<string>` | Emits on value change |
402
+ | `iconClick` | `EventEmitter<void>` | Emits when icon is clicked |
403
+
125
404
  ---
126
405
 
127
- ### 2. `ButtonContainerComponent`
406
+ #### InputStepperComponent
128
407
 
129
- A container for standard buttons.
408
+ A numeric stepper input with increment/decrement buttons.
130
409
 
131
- - **Selector**: `app-button-container`
132
- - **Inputs**:
133
- - `size: 'xs' | 'sm' | 'md' | 'lg'`: Size of the button (default: `'md'`).
134
- - `content: string`: Text content of the button.
135
- - `leftIcon: string`: CSS class or content for left icon.
136
- - `rightIcon: string`: CSS class or content for right icon.
137
- - `color: string`: Text color (default: `var(--brand-100)`).
138
- - `backgroundColor: string`: Background color (default: `var(--utility-900)`).
139
- - `borderColor: string`: Border color (default: `var(--brand-100)`).
140
- - `fontSize: string`: Custom font size.
141
- - **Outputs**:
142
- - `buttonClick`: Event emitted when button is clicked.
410
+ **Selector:** `app-input-stepper`
411
+
412
+ ```typescript
413
+ import { InputStepperComponent } from "@goat-bravos/intern-hub-layout";
414
+
415
+ @Component({
416
+ imports: [InputStepperComponent],
417
+ template: `
418
+ <!-- Basic stepper -->
419
+ <app-input-stepper headerInput="Quantity" [(value)]="quantity" [min]="1" [max]="100" [step]="1"></app-input-stepper>
143
420
 
144
- ### 3. `LabelButtonComponent`
421
+ <!-- Stepper with helper text -->
422
+ <app-input-stepper headerInput="Age" [(value)]="age" [min]="0" [max]="120" helperText="Enter your age" [required]="true"></app-input-stepper>
145
423
 
146
- A small button-like label.
424
+ <!-- Disabled stepper -->
425
+ <app-input-stepper headerInput="Fixed Value" [value]="10" [disabled]="true"></app-input-stepper>
426
+ `,
427
+ })
428
+ export class MyComponent {
429
+ quantity = 1;
430
+ age = 25;
431
+ }
432
+ ```
147
433
 
148
- - **Selector**: `app-label-button`
149
- - **Inputs**:
150
- - `label: string`: Text content.
151
- - `bgColor: string`: Background color.
152
- - `borderColor: string`: Border color.
153
- - `textColor: string`: Text color.
154
- - `width: string`: Width of the component (default: `100%`).
155
- - `height: string`: Height of the component (default: `28px`).
434
+ **Inputs:**
435
+
436
+ | Input | Type | Default | Description |
437
+ | ------------- | --------------------------------------- | ----------- | ----------------- |
438
+ | `headerInput` | `string` | `''` | Label text |
439
+ | `value` | `number` | `0` | Current value |
440
+ | `min` | `number` | `0` | Minimum value |
441
+ | `max` | `number` | `100` | Maximum value |
442
+ | `step` | `number` | `1` | Step increment |
443
+ | `placeholder` | `string` | `''` | Input placeholder |
444
+ | `readonly` | `boolean` | `false` | Read-only state |
445
+ | `required` | `boolean` | `false` | Required state |
446
+ | `disabled` | `boolean` | `false` | Disabled state |
447
+ | `width` | `string` | `'100%'` | Component width |
448
+ | `error` | `string` | `''` | Error message |
449
+ | `helperText` | `string` | `''` | Helper text below |
450
+ | `state` | `'default' \| 'negative' \| 'positive'` | `'default'` | Visual state |
451
+
452
+ **Outputs:**
453
+
454
+ | Output | Type | Description |
455
+ | ------------- | ---------------------- | --------------------- |
456
+ | `valueChange` | `EventEmitter<number>` | Emits on value change |
156
457
 
157
458
  ---
158
459
 
159
- ### 4. `InputTextComponent`
160
-
161
- Standard text input field.
162
-
163
- - **Selector**: `app-input-text`
164
- - **Inputs**:
165
- - `headerInput: string`: Label text above the input.
166
- - `placeholder: string`: Placeholder text.
167
- - `value: string`: Initial value (supports binding).
168
- - `readonly: boolean`: If true, input is read-only.
169
- - `required: boolean`: If true, shows required asterisk.
170
- - `width: string`: Width of the input container (default: `100%`).
171
- - `maxLength: number`: Maximum character length.
172
- - `showLimit: boolean`: Whether to show character count.
173
- - `icon: string`: Icon class to display inside input.
174
- - `typeInput: string`: Input type (e.g., `'text'`, `'password'`).
175
- - **Outputs**:
176
- - `valueChange`: Emits new value on input.
177
- - `iconClick`: Emits when the icon is clicked.
178
-
179
- ### 5. `InputStepperComponent`
180
-
181
- Number input with increment/decrement buttons.
182
-
183
- - **Selector**: `app-input-stepper`
184
- - **Inputs**:
185
- - `headerInput`: Label text.
186
- - `value: number`: Initial value.
187
- - `min`: Minimum value (default: 0).
188
- - `max`: Maximum value (default: 100).
189
- - `step`: Step value (default: 1).
190
- - `state`: Visual state (`'default'`, `'negative'`, `'positive'`).
191
- - `helperText`: Text displayed below the input.
192
- - `readonly`, `required`, `disabled`, `width`.
193
- - **Outputs**:
194
- - `valueChange`: Emits new numeric value.
195
-
196
- ### 6. `InputCalendarComponent`
197
-
198
- Date picker input.
199
-
200
- - **Selector**: `app-input-calendar`
201
- - **Inputs**:
202
- - `headerInput`: Label text.
203
- - `value: string`: Date value in ISO format (`yyyy-mm-dd`).
204
- - `placeholder`: Placeholder text (default: `'dd/mm/yyyy'`).
205
- - `readonly`, `required`, `width`.
206
- - **Outputs**:
207
- - `valueChange`: Emits selected date in ISO format.
460
+ #### InputCalendarComponent
461
+
462
+ A date picker with auto-formatting (dd/mm/yyyy) and validation.
463
+
464
+ **Selector:** `app-input-calendar`
465
+
466
+ ```typescript
467
+ import { InputCalendarComponent } from "@goat-bravos/intern-hub-layout";
468
+
469
+ @Component({
470
+ imports: [InputCalendarComponent],
471
+ template: `
472
+ <!-- Basic date picker -->
473
+ <app-input-calendar headerInput="Start Date" [(value)]="startDate" (valueChange)="onDateChange($event)"></app-input-calendar>
474
+
475
+ <!-- Required date picker -->
476
+ <app-input-calendar headerInput="Birth Date" [required]="true" [(value)]="birthDate"></app-input-calendar>
477
+
478
+ <!-- Read-only date -->
479
+ <app-input-calendar headerInput="Created At" [readonly]="true" [value]="createdAt"></app-input-calendar>
480
+ `,
481
+ })
482
+ export class MyComponent {
483
+ startDate = ""; // ISO format: '2024-01-15'
484
+ birthDate = "";
485
+ createdAt = "2024-01-01";
486
+
487
+ onDateChange(isoDate: string) {
488
+ console.log("Date selected:", isoDate); // Output: '2024-01-15'
489
+ }
490
+ }
491
+ ```
492
+
493
+ **Inputs:**
494
+
495
+ | Input | Type | Default | Description |
496
+ | ------------- | --------- | -------------- | ----------------------------------- |
497
+ | `headerInput` | `string` | `''` | Label text |
498
+ | `value` | `string` | `''` | Date value (ISO format: yyyy-mm-dd) |
499
+ | `placeholder` | `string` | `'dd/mm/yyyy'` | Placeholder text |
500
+ | `readonly` | `boolean` | `false` | Read-only state |
501
+ | `required` | `boolean` | `false` | Required state |
502
+ | `width` | `string` | `'100%'` | Component width |
503
+
504
+ **Outputs:**
505
+
506
+ | Output | Type | Description |
507
+ | ------------- | ---------------------- | --------------------------------- |
508
+ | `valueChange` | `EventEmitter<string>` | Emits ISO date on valid selection |
509
+
510
+ > **Note:** The calendar validates dates and only emits valid dates. Invalid dates like `31/02/2024` will not trigger a valueChange event.
208
511
 
209
512
  ---
210
513
 
211
- ### 7. `TableHeaderComponent`
514
+ ### Table Components
515
+
516
+ #### TableHeaderComponent & TableBodyComponent
517
+
518
+ Table components with customizable columns and template support.
212
519
 
213
- Renders table headers.
520
+ **Selectors:** `tr[app-table-header]`, `tbody[app-table-body]`
214
521
 
215
- - **Selector**: `tr[app-table-header]` (Attribute on `<tr>`)
216
- - **Inputs**:
217
- - `columns: ColumnConfig[]`: Array of column configurations.
218
- - `backgroundColor`: Header background color.
219
- - `textColor`: Text color (default: white).
220
- - `headerIconLeft`, `headerIconRight`: Icons for header cells.
522
+ ```typescript
523
+ import { TableHeaderComponent, TableBodyComponent, ColumnConfig } from "@goat-bravos/intern-hub-layout";
524
+ import { CommonModule } from "@angular/common";
525
+
526
+ @Component({
527
+ imports: [CommonModule, TableHeaderComponent, TableBodyComponent],
528
+ template: `
529
+ <table class="data-table">
530
+ <thead>
531
+ <tr app-table-header [columns]="columns" backgroundColor="#1e293b" textColor="#ffffff"></tr>
532
+ </thead>
533
+ <tbody app-table-body [columns]="columns" [rows]="users" [columnTemplates]="{ status: statusTemplate }"></tbody>
534
+ </table>
535
+
536
+ <!-- Custom template for status column -->
537
+ <ng-template #statusTemplate let-value let-row="row">
538
+ <app-label-button [label]="value" [bgColor]="value === 'Active' ? '#22c55e' : '#ef4444'" textColor="#ffffff"></app-label-button>
539
+ </ng-template>
540
+ `,
541
+ })
542
+ export class MyComponent {
543
+ columns: ColumnConfig[] = [
544
+ { header: "ID", key: "id", width: "80px" },
545
+ { header: "Name", key: "name", width: "200px" },
546
+ { header: "Email", key: "email", width: "250px" },
547
+ { header: "Status", key: "status", width: "120px" },
548
+ ];
549
+
550
+ users = [
551
+ { id: 1, name: "John Doe", email: "john@example.com", status: "Active" },
552
+ { id: 2, name: "Jane Smith", email: "jane@example.com", status: "Inactive" },
553
+ { id: 3, name: "Bob Wilson", email: "bob@example.com", status: "Active" },
554
+ ];
555
+ }
556
+ ```
221
557
 
222
- #### Interface `ColumnConfig`
558
+ **ColumnConfig Interface:**
223
559
 
224
560
  ```typescript
225
561
  interface ColumnConfig {
226
- header: string; // Display text
227
- key: string; // Data key
228
- width: string; // CSS width
562
+ header: string; // Display header text
563
+ key: string; // Property key in data object
564
+ width: string; // Column width (CSS value)
229
565
  }
230
566
  ```
231
567
 
232
- ### 8. `TableBodyComponent`
568
+ **TableHeaderComponent Inputs:**
233
569
 
234
- Renders table rows.
570
+ | Input | Type | Default | Description |
571
+ | ----------------- | ---------------- | ------------------ | ---------------------- |
572
+ | `columns` | `ColumnConfig[]` | `[]` | Column definitions |
573
+ | `backgroundColor` | `string` | - | Header background |
574
+ | `textColor` | `string` | `'#ffffff'` | Text color |
575
+ | `headerIconLeft` | `string` | - | Left icon for columns |
576
+ | `headerIconRight` | `string` | - | Right icon for columns |
577
+ | `fontSize` | `string` | `'var(--font-xs)'` | Font size |
235
578
 
236
- - **Selector**: `tbody[app-table-body]` (Attribute on `<tbody>`)
237
- - **Inputs**:
238
- - `rows: any[]`: Array of data objects.
239
- - `columns: ColumnConfig[]`: Column configuration to map data.
240
- - `columnTemplates`: Object mapping column keys to `TemplateRef` for custom cell rendering.
579
+ **TableBodyComponent Inputs:**
580
+
581
+ | Input | Type | Default | Description |
582
+ | ----------------- | ------------------------------------- | ------------------ | --------------------- |
583
+ | `rows` | `any[]` | `[]` | Data array |
584
+ | `columns` | `ColumnConfig[]` | `[]` | Column definitions |
585
+ | `columnTemplates` | `{ [key: string]: TemplateRef<any> }` | `{}` | Custom cell templates |
586
+ | `fontSize` | `string` | `'var(--font-sm)'` | Font size |
241
587
 
242
588
  ---
243
589
 
244
- ### 9. `ApprovalListComponent`
590
+ ### Approval Components
591
+
592
+ #### ApprovalListComponent
593
+
594
+ A list component for displaying approval workflows with customizable right-side templates.
595
+
596
+ **Selector:** `app-approval-list`
597
+
598
+ ```typescript
599
+ import { ApprovalListComponent, ApprovalListItemInterface, ButtonContainerComponent } from "@goat-bravos/intern-hub-layout";
600
+ import { CommonModule } from "@angular/common";
601
+
602
+ @Component({
603
+ imports: [CommonModule, ApprovalListComponent, ButtonContainerComponent],
604
+ template: `
605
+ <app-approval-list [rows]="approvalItems" headerContentLeft="Applicant" headerContentRight="Actions" width="600px"></app-approval-list>
606
+
607
+ <!-- Template for action buttons -->
608
+ <ng-template #actionsTemplate let-row="row">
609
+ <div class="action-buttons">
610
+ <app-button-container content="Approve" size="xs" backgroundColor="#22c55e" (buttonClick)="approve(row)"></app-button-container>
611
+ <app-button-container content="Reject" size="xs" backgroundColor="#ef4444" (buttonClick)="reject(row)"></app-button-container>
612
+ </div>
613
+ </ng-template>
614
+ `,
615
+ })
616
+ export class MyComponent {
617
+ @ViewChild("actionsTemplate") actionsTemplate!: TemplateRef<any>;
618
+
619
+ approvalItems: ApprovalListItemInterface[] = [];
620
+
621
+ ngAfterViewInit() {
622
+ this.approvalItems = [
623
+ {
624
+ name: "John Doe - Leave Request",
625
+ date: new Date("2024-01-15"),
626
+ rightTemplate: this.actionsTemplate,
627
+ rightContext: { row: { id: 1, type: "leave" } },
628
+ },
629
+ {
630
+ name: "Jane Smith - Expense Report",
631
+ date: new Date("2024-01-14"),
632
+ rightTemplate: this.actionsTemplate,
633
+ rightContext: { row: { id: 2, type: "expense" } },
634
+ },
635
+ ];
636
+ }
637
+
638
+ approve(row: any) {
639
+ console.log("Approved:", row);
640
+ }
641
+
642
+ reject(row: any) {
643
+ console.log("Rejected:", row);
644
+ }
645
+ }
646
+ ```
647
+
648
+ **ApprovalListItemInterface:**
649
+
650
+ ```typescript
651
+ interface ApprovalListItemInterface {
652
+ name: string;
653
+ date: Date;
654
+ rightTemplate?: TemplateRef<any>;
655
+ rightContext?: any;
656
+ }
657
+ ```
658
+
659
+ ---
660
+
661
+ ### Pop-up Components
662
+
663
+ #### PopUpConfirmComponent
664
+
665
+ An accessible confirmation modal dialog.
666
+
667
+ **Selector:** `app-pop-up-confirm`
668
+
669
+ ```typescript
670
+ import { PopUpConfirmComponent } from "@goat-bravos/intern-hub-layout";
671
+ import { CommonModule } from "@angular/common";
672
+
673
+ @Component({
674
+ imports: [CommonModule, PopUpConfirmComponent],
675
+ template: `
676
+ <button (click)="showConfirm = true">Delete Item</button>
677
+
678
+ @if (showConfirm) {
679
+ <app-pop-up-confirm title="Confirm Delete" content="Are you sure you want to delete this item? This action cannot be undone." imgUrl="assets/warning-icon.svg" colorButton="#ef4444" (confirmClick)="onConfirm()" (cancelClick)="onCancel()"></app-pop-up-confirm>
680
+ }
681
+ `,
682
+ })
683
+ export class MyComponent {
684
+ showConfirm = false;
685
+
686
+ onConfirm() {
687
+ console.log("Confirmed!");
688
+ this.showConfirm = false;
689
+ // Perform delete action
690
+ }
691
+
692
+ onCancel() {
693
+ console.log("Cancelled");
694
+ this.showConfirm = false;
695
+ }
696
+ }
697
+ ```
698
+
699
+ **Inputs:**
700
+
701
+ | Input | Type | Default | Description |
702
+ | ------------- | -------- | -------------------- | -------------------- |
703
+ | `title` | `string` | `''` | Modal title |
704
+ | `content` | `string` | `''` | Message content |
705
+ | `imgUrl` | `string` | `''` | Icon/image URL |
706
+ | `colorButton` | `string` | `'var(--brand-600)'` | Confirm button color |
707
+
708
+ **Outputs:**
709
+
710
+ | Output | Type | Description |
711
+ | -------------- | -------------------- | ---------------------- |
712
+ | `confirmClick` | `EventEmitter<void>` | Emits on confirm click |
713
+ | `cancelClick` | `EventEmitter<void>` | Emits on cancel click |
714
+
715
+ ---
245
716
 
246
- A list component showing approval items.
717
+ ### Icon Components
247
718
 
248
- - **Selector**: `app-approval-list`
249
- - **Inputs**:
250
- - `rows: ApprovalListItemInterface[]`: List of items.
251
- - `headerContentLeft`: Text for left header.
252
- - `headerContentRight`: Text for right header.
253
- - `width`: Component width.
719
+ #### IconComponent
254
720
 
255
- ### 10. `PopUpConfirmComponent`
721
+ A flexible icon component supporting icon libraries and custom styling.
256
722
 
257
- A confirmation modal.
723
+ **Selector:** `app-icon`
724
+
725
+ ```typescript
726
+ import { IconComponent, IconData } from "@goat-bravos/intern-hub-layout";
727
+
728
+ @Component({
729
+ imports: [IconComponent],
730
+ template: `
731
+ <!-- Using IconData object -->
732
+ <app-icon [iconData]="settingsIcon"></app-icon>
733
+
734
+ <!-- Using individual inputs -->
735
+ <app-icon icon="dsi-home-01-line" colorIcon="#3b82f6" width="24px" height="24px" (clicked)="onIconClick()"></app-icon>
736
+ `,
737
+ })
738
+ export class MyComponent {
739
+ settingsIcon: IconData = {
740
+ icon: "dsi-settings-line",
741
+ colorIcon: "#666666",
742
+ width: "20px",
743
+ height: "20px",
744
+ routerLink: "/settings",
745
+ };
746
+
747
+ onIconClick() {
748
+ console.log("Icon clicked");
749
+ }
750
+ }
751
+ ```
752
+
753
+ **IconData Interface:**
754
+
755
+ ```typescript
756
+ interface IconData {
757
+ icon: string;
758
+ colorIcon?: string;
759
+ routerLink?: string;
760
+ width?: string;
761
+ height?: string;
762
+ }
763
+ ```
764
+
765
+ ---
766
+
767
+ #### FunctionalLabelComponent
768
+
769
+ A label component with icons and hover effects, commonly used in sidebars.
770
+
771
+ **Selector:** `app-functional-label`
772
+
773
+ ```typescript
774
+ import { FunctionalLabelComponent, IconData } from "@goat-bravos/intern-hub-layout";
775
+
776
+ @Component({
777
+ imports: [FunctionalLabelComponent],
778
+ template: ` <app-functional-label content="Dashboard" [iconLeft]="dashboardIcon" routerLink="/dashboard" backgroundColor="transparent" backgroundColorHover="#3b82f6" colorContent="#666" colorContentHover="#fff" (clicked)="onLabelClick($event)"></app-functional-label> `,
779
+ })
780
+ export class MyComponent {
781
+ dashboardIcon: IconData = {
782
+ icon: "dsi-home-01-line",
783
+ colorIcon: "#666",
784
+ };
785
+
786
+ onLabelClick(event: Event) {
787
+ console.log("Label clicked", event);
788
+ }
789
+ }
790
+ ```
791
+
792
+ ---
793
+
794
+ ## 🛠️ Development
795
+
796
+ ### Prerequisites
797
+
798
+ - Node.js 18+
799
+ - npm 9+
800
+ - Angular CLI 21+
801
+
802
+ ### Building the Library
803
+
804
+ ```bash
805
+ # Install dependencies
806
+ npm install
807
+
808
+ # Build for production
809
+ npm run build
810
+
811
+ # Build and pack for local testing
812
+ npm run pack:lib
813
+ ```
814
+
815
+ ### Publishing
816
+
817
+ ```bash
818
+ # Dry run (test publish)
819
+ npm run publish:lib:dry
820
+
821
+ # Publish to npm
822
+ npm run publish:lib
823
+ ```
824
+
825
+ ### Project Structure
826
+
827
+ ```
828
+ intern-hub-fe-layout/
829
+ ├── src/
830
+ │ ├── libs/
831
+ │ │ ├── layouts/ # Layout components
832
+ │ │ │ ├── header/ # Header component
833
+ │ │ │ └── sidebar/ # Sidebar component
834
+ │ │ └── shared/
835
+ │ │ └── components/ # Shared UI components
836
+ │ │ ├── button/ # Button components
837
+ │ │ ├── input/ # Input components
838
+ │ │ ├── table/ # Table components
839
+ │ │ ├── approval/ # Approval list components
840
+ │ │ ├── pop-up/ # Pop-up/modal components
841
+ │ │ ├── icon/ # Icon component
842
+ │ │ └── functional-label/
843
+ │ └── public-api.ts # Public exports
844
+ ├── ng-package.json # ng-packagr config
845
+ ├── package.json
846
+ └── README.md
847
+ ```
848
+
849
+ ---
850
+
851
+ ## 🤝 Contributing
852
+
853
+ Contributions are welcome! Please feel free to submit a Pull Request.
854
+
855
+ 1. Fork the repository
856
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
857
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
858
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
859
+ 5. Open a Pull Request
860
+
861
+ ---
862
+
863
+ ## 📄 License
864
+
865
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
866
+
867
+ ---
868
+
869
+ ## 👥 Author
870
+
871
+ **Intern Hub Team**
872
+
873
+ - Repository: [GitHub](https://github.com/FPT-IS-Intern/Intern-Hub-FE-Layout)
874
+
875
+ ---
258
876
 
259
- - **Selector**: `app-pop-up-confirm`
260
- - **Inputs**:
261
- - `title`: Popup title.
262
- - `content`: Message body.
263
- - `imgUrl`: Icon/Image URL.
264
- - `colorButton`: Color of the confirm button.
265
- - **Outputs**:
266
- - `confirmClick`: Emits when confirmed.
267
- - `cancelClick`: Emits when canceled.
877
+ <div align="center">
878
+ <sub>Built with ❤️ by Intern Hub Team</sub>
879
+ </div>