@sixbell-telco/sdk
Version:
A collection of reusable components designed for use in Sixbell Telco Angular projects
1,171 lines (990 loc) • 35.8 kB
Markdown
# Sixbell Telco SDK - Component Library
Welcome to the Sixbell Telco SDK component library. This is a comprehensive Angular component library featuring 25+ pre-built, production-ready UI components built with Angular 19, Tailwind CSS v4, and DaisyUI.
## Overview
The SDK provides:
- **25+ Production-Ready Components**: Button, Card, Form inputs, Data Table, Dialog, Dropdown, and more
- **Utility Services**: Theme management, i18n translation, logging, and resource loading
- **Directive Support**: Auto-focus, click-outside, form validation directives
- **Tailwind CSS v4 + DaisyUI**: Modern styling with customizable themes
- **Multi-Entry Point Architecture**: Granular imports for optimized bundle sizes
- **Angular 19 Signal-Based**: Modern reactive patterns with Angular signals
## Pre-requirements
- **Node.js**: ^18.19.1 || ^20.11.1 || ^22.0.0
- **npm**: 9.6.7 || ^10.0.0 || ^11.0.0
- **Angular**: 19.2.x or later
- **Tailwind CSS**: v4.x
## Available Components
### General Components
| Component | Description |
| ------------- | ------------------------------------------------- |
| Accordion | Expandable/collapsible content sections |
| Avatar | User profile pictures with initials fallback |
| Badge | Status and label indicators |
| Button | Interactive buttons with variants and sizes |
| Card | Container for content with actions |
| Countdown | Countdown timer with customizable formatting |
| Data Table | Advanced grid with sorting, filtering, pagination |
| Dialog | Modal dialogs with animations and positioning |
| Dropdown | Menu dropdown for actions and links |
| Dropdown Menu | Advanced nested menu system |
| Dual List | Dual list selection for managing items |
| File Dropzone | Drag-and-drop file upload with validation |
| File Uploader | File input with validation and preview |
| Icon | SVG icon component with ng-icons integration |
| Link | Hyperlink component with router support |
| Modal | Modal dialogs (legacy - use Dialog instead) |
| Notification | Toast-style notifications |
| Overlay | Generic overlay with trigger and content |
| Paginator | Pagination controls for data |
| Product Card | Product display card with image and actions |
| Progress | Progress bar with variants |
| Sonner Toast | Modern toast notifications via ngx-sonner |
| Tab | Tabbed navigation interface |
| Table | Basic table for displaying data |
| Tooltip | Floating tooltip with positioning |
| Wizard | Multi-step wizard with validation |
### Form Components
| Component | Description |
| ---------- | ----------------------------------------------- |
| Checkbox | Checkbox input with multiple variants |
| Combobox | Searchable dropdown with multi-select support |
| Datepicker | Single and range date selection with time |
| Form Error | Error message display for form fields |
| Input | Text input with variants, icons, and validation |
| Radio | Radio button group selection |
| Range | Slider input for numeric ranges |
| Select | Dropdown select with object support |
| Switch | Toggle switch for boolean values |
| Textarea | Multi-line text input with character count |
| Toggle | Toggle button for boolean states |
### Utility Services
| Service | Purpose | Documentation |
| ------------------- | -------------------------------------------------- | ------------------------------- |
| Logger Service | Theme-aware logging with IndexedDB persistence | [README](utils/logger/) |
| Theme Service | Runtime theme management with multi-tenant support | [README](utils/theme/) |
| Translation Service | Multi-language i18n with ngx-translate integration | [README](utils/translation/) |
| Runtime Config | Last-known-good runtime config loader | [README](utils/runtime-config/) |
### Directives
| Directive | Purpose |
| ------------- | ---------------------------------------- |
| auto-focus | Auto-focus elements when visible |
| click-outside | Detect clicks outside an element |
| only-numbers | Restrict input to numeric values only |
| typography | Apply typography styles to text elements |
## Installation
### Step 1: Install Dependencies
```bash
npm install @sixbell-telco/sdk @tailwindcss/typography daisyui @midudev/tailwind-animations
```
### Step 2: Import SDK Styles
In your global `styles.css`:
```css
@import '../node_modules/@sixbell-telco/sdk/_index.css';
@import 'tailwindcss';
@source '../src';
```
> ⚠️ **Important**: Import `_index.css` **before** the tailwind import.
### Step 3: Configure Microfrontend (if applicable)
Add path mapping to `tsconfig.json`:
```json
{
"compilerOptions": {
"paths": {
"@sixbell-telco/sdk/*": ["./node_modules/@sixbell-telco/sdk/*"]
}
}
}
```
### Step 4: Optional - VSCode Configuration
Install the Tailwind CSS extension and add to `.vscode/settings.json`:
```json
{
"editor.quickSuggestions": {
"strings": "on"
},
"files.associations": {
"*.css": "tailwindcss"
},
"tailwindCSS.classFunctions": ["tw", "clsx", "cva", "cn", "tw\\.[a-z-]+"]
}
```
These settings improve your development experience:
- `editor.quickSuggestions`: Enables autosuggestions within string literals
- `files.associations`: Ensures CSS files are treated as Tailwind CSS files
- `tailwindCSS.classFunctions`: Enables Tailwind intellisense in utility functions like `tw()`, `clsx()`, and `cva()`, etc that are used for conditional class name composition
With these settings, VSCode will provide class autocompletion for the library's custom attributes and utility functions.
## Themes and translation configuration (an optional Logger)
Configure all services using runtime providers in your `app.config.ts`. This approach loads configuration from JSON files at runtime, eliminating the need to recompile when updating themes or languages.
### Logger Service Setup
Configure logging with different levels for development and production:
```typescript
import { provideLogger } from '@sixbell-telco/sdk/utils/logger';
export const appConfig: ApplicationConfig = {
providers: [
provideLogger({
enableLogging: true,
logLevel: isDevMode() ? 'debug' : 'warn', // trace | debug | info | warn | error | fatal
showTimestamp: true,
persistToIndexedDB: true, // Persistent storage for debugging
silentMode: !isDevMode(),
}),
],
};
```
### Translation Service Setup
The Translation Service loads language configuration from a runtime JSON file:
```typescript
import { provideRuntimeTranslation } from '@sixbell-telco/sdk/utils/translation';
export const appConfig: ApplicationConfig = {
providers: [provideRuntimeTranslation('/assets/translation/translation.json')],
};
```
The `translation.json` file defines available languages and their translation paths:
```json
{
"defaultLang": "es",
"translationPaths": ["/assets/i18n/"]
}
```
### Theme Service Setup
The Theme Service loads theme configuration from a runtime JSON file:
```typescript
import { provideRuntimeTheme } from '@sixbell-telco/sdk/utils/theme';
export const appConfig: ApplicationConfig = {
providers: [provideRuntimeTheme('/assets/themes/themes.json')],
};
```
The `themes.json` file defines available themes and their variants:
```json
{
"meta": {
"name": "themes",
"updatedAt": "2026-02-02T00:00:00Z",
"hash": "themes-v2",
"schemaVersion": "2"
},
"themes": ["/assets/themes/catalog/sixbell_telco.json", "/assets/themes/catalog/custom_theme.json"],
"defaultTheme": "sixbell_telco",
"defaultScheme": "system",
"excludeThemes": []
}
```
### Complete Configuration Example
```typescript
// app.config.ts
import { DialogModule } from '@angular/cdk/dialog';
import { ApplicationConfig, importProvidersFrom, isDevMode } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { provideLogger } from '@sixbell-telco/sdk/utils/logger';
import { provideRuntimeTheme } from '@sixbell-telco/sdk/utils/theme';
import { provideRuntimeTranslation } from '@sixbell-telco/sdk/utils/translation';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(),
// CDK Dialog providers (required for dialog component)
importProvidersFrom(DialogModule),
// Logger service - configure logging levels and storage
provideLogger({
enableLogging: true,
logLevel: isDevMode() ? 'debug' : 'warn',
showTimestamp: true,
persistToIndexedDB: true,
silentMode: !isDevMode(),
}),
// Translation service - loads languages from runtime JSON
provideRuntimeTranslation('/assets/translation/translation.json'),
// Theme service - loads themes from runtime JSON
provideRuntimeTheme('/assets/themes/themes.json'),
],
};
```
**Key Benefits of Runtime Configuration:**
- **No Recompilation**: Update themes and languages without rebuilding your application
- **Multi-Tenant Support**: Easily switch themes and language sets per deployment environment
- **Caching Strategy**: RuntimeConfigStore keeps last-known-good config in Dexie
- **Hot Updates**: Changes to `themes.json` and `translation.json` take effect immediately
- **Persistent Preferences**: User language and theme preferences are stored and restored automatically
## Adding Custom Themes
Themes are managed through a runtime configuration file (`themes.json`) with theme JSON files. This approach allows for:
- **Zero Recompilation**: Add/modify themes without rebuilding
- **Multi-Tenant Support**: Different themes per deployment
- **Dynamic Assets**: Brand-specific logos and images per theme
- **Runtime Fonts**: Load custom fonts for each theme
- **Hot Updates**: Changes take effect immediately
### 1. Update `themes.json`
Add your custom theme to `/assets/themes/themes.json`:
```json
{
"meta": {
"name": "themes",
"updatedAt": "2026-02-02T00:00:00Z",
"hash": "themes-v2",
"schemaVersion": "2"
},
"themes": ["/assets/themes/catalog/sixbell_telco.json", "/assets/themes/catalog/custom_theme.json"],
"defaultTheme": "sixbell_telco",
"defaultScheme": "system",
"excludeThemes": []
}
```
**Configuration Structure:**
- `themes`: Theme JSON paths
- `defaultTheme`: Initial theme on app startup
- `defaultScheme`: Initial color scheme (`'system'`, `'light'`, or `'dark'`)
### 2. Define DaisyUI Themes in Global Styles
In your global `styles.css`, import the SDK and define your theme CSS:
```css
@import '../node_modules/@sixbell-telco/sdk/_index.css';
@import 'tailwindcss';
@source '../src';
```
### 3. Use Themes in Components
The ThemeService automatically loads available themes from `themes.json`:
```typescript
import { Component, ChangeDetectionStrategy, inject, computed } from '@angular/core';
import { ThemeService, ThemeAssetsService } from '@sixbell-telco/sdk/utils/theme';
import { ButtonComponent } from '@sixbell-telco/sdk/components/button';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-theme-switcher',
standalone: true,
imports: [CommonModule, ButtonComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div>
<select (change)="themeService.setTheme($event.target.value)">
@for (theme of themeService.getAvailableThemes(); track theme) {
<option [value]="theme" [selected]="themeService.selectedTheme() === theme">
{{ themeService.getLocalizedThemeName(theme) }}
</option>
}
</select>
<select (change)="themeService.setScheme($event.target.value)">
@for (scheme of themeService.getAvailableSchemes(); track scheme) {
<option [value]="scheme" [selected]="themeService.selectedScheme() === scheme">
{{ themeService.getLocalizedSchemeName(scheme) }}
</option>
}
</select>
<img [src]="logoUrl()" alt="Brand Logo" />
</div>
`,
})
export class ThemeSwitcherComponent {
themeService = inject(ThemeService);
private assetsService = inject(ThemeAssetsService);
logoUrl = computed(
() => this.assetsService.getAssetUrl(this.themeService.selectedTheme(), 'logo', this.themeService.resolvedScheme()) || '/default-logo.svg',
);
}
```
### 4. Add Theme Names to Translations
Store theme and scheme display names in translation files. Create `/assets/themes/i18n/en.json`:
**English (`en.json`):**
```json
{
"sdk": {
"theme": {
"themes": {
"sixbell_telco": "Sixbell Telco",
"custom_theme": "Custom Theme"
},
"schemes": {
"system": "System",
"light": "Light",
"dark": "Dark"
}
}
}
}
```
**Spanish (`es.json`):**
```json
{
"sdk": {
"theme": {
"themes": {
"sixbell_telco": "Sixbell Telco",
"custom_theme": "Tema Personalizado"
},
"schemes": {
"system": "Sistema",
"light": "Claro",
"dark": "Oscuro"
}
}
}
}
```
**Portuguese (`pt.json`):**
```json
{
"sdk": {
"theme": {
"themes": {
"sixbell_telco": "Sixbell Telco",
"custom_theme": "Tema Personalizado"
},
"schemes": {
"system": "Sistema",
"light": "Claro",
"dark": "Escuro"
}
}
}
}
```
Your themes are now fully configured. The ThemeService automatically:
- Loads theme definitions from `themes.json`
- Injects CSS variables via signals
- Resolves dynamic assets based on current theme and scheme
- Persists user preferences to localStorage
- Detects system dark mode preference when scheme is set to `'system'`
## Adding Custom Languages
Languages are now managed through a runtime configuration file (`translation.json`), eliminating the need to reconfigure and recompile. This approach allows for:
- **Zero Recompilation**: Add or modify languages without rebuilding
- **Multi-Tenant Languages**: Different language sets per deployment environment
- **Hot Updates**: Changes to translation configuration take effect immediately
- **Flexible Structure**: Organize translation files any way you need
### 1. Create or Update `translation.json`
Create `/assets/translation/translation.json` in your application:
```json
{
"defaultLang": "es",
"translationPaths": ["/assets/i18n/"]
}
```
**Configuration Structure:**
- `defaultLang`: Language code used on app initialization
- `translationPaths`: List of directories that contain `{lang}.json`
- Custom paths are fully supported - organize as needed for your architecture
### 2. Create Translation Files
Create language translation files at the paths defined in `translation.json`. The minimal translation structure includes SDK translations:
**English (`/assets/sdk/i18n/en.json`):**
```json
{
"sdk": {
"fileUpload": {
"dropzone": {
"selectPrompt": "Click to select files or drag and drop here",
"maxSizeLabel": "Max size:",
"allowedTypesLabel": "Allowed types:",
"invalidFileType": "Invalid file type",
"fileTooLarge": "File too large",
"fileCounter": "{{current}} of {{max}} files",
"maxFilesExceeded": "Maximum {{max}} file(s) allowed",
"noValidFiles": "No valid files selected",
"fileActions": {
"play": "Play audio",
"pause": "Pause audio",
"download": "Download file",
"remove": "Remove file"
}
},
"fileUploader": {
"allowedTypesLabel": "Allowed types:"
}
},
"audioPlayer": {
"trackListTitle": "Tracks",
"trackInfo": {
"title": "No title",
"description": "No description"
}
},
"countdown": {
"days": "Days",
"hours": "Hours",
"minutes": "Minutes",
"seconds": "Seconds"
},
"dualList": {
"searchPlaceHolder": "Search"
},
"combobox": {
"searchPlaceholder": "Search",
"placeholder": "Select",
"noResultsFound": "No results found",
"clearAll": "Clear All",
"clearSelection": "Clear selection",
"searchOptions": "Search options",
"loading": "Loading..."
},
"select": {
"placeholder": "Select"
},
"formErrors": {
"validation": {
"required": "*This field is required",
"email": "*Please enter a valid email address",
"minLength": "*Must be at least {{min}} characters",
"maxLength": "*Must be no more than {{max}} characters",
"min": "*Value must be at least {{min}}",
"max": "*Value must be no more than {{max}}",
"pattern": "*Invalid format",
"unhandledError": "*Unhandled error"
}
},
"textarea": {
"maxCharacters": "{{current}} of {{max}} characters"
},
"table": {
"entriesByPage": "Entries per page",
"perPage": "{{count}} / page",
"totalEntries": "{{total}} entries",
"entriesRange": "{{range}} of {{total}} entries",
"emptyListMessage": "No items to show"
},
"dataTable": {
"entriesByPage": "Entries per page",
"perPage": "{{count}} / page",
"totalEntries": "{{total}} entries",
"entriesRange": "{{range}} of {{total}} entries",
"emptyListMessage": "No items to show",
"noData": {
"title": "No data available",
"message": "There are no records to display at this time."
},
"noResults": {
"title": "No results found",
"message": "Try adjusting your search criteria"
}
},
"wizard": {
"wizardMarker": {
"completed": "Completed",
"inProgress": "In progress",
"pending": "Pending"
},
"wizardWrapper": {
"back": "Back",
"previous": "Previous",
"end": "End",
"next": "Next",
"step": "Step {{index}}"
}
},
"datePicker": {
"quickActions": {
"title": "Quick Select",
"lastHour": "Last hour",
"last3Hours": "Last 3 hours",
"last6Hours": "Last 6 hours",
"last12Hours": "Last 12 hours",
"last24Hours": "Last 24 hours",
"last7Days": "Last 7 days",
"last30Days": "Last 30 days",
"last6Months": "Last 6 months",
"lastYear": "Last year",
"clear": "Clear"
},
"labels": {
"from": "From",
"to": "To"
}
}
}
}
```
**Spanish (`/assets/i18n/es.json`):**
```json
{
"sdk": {
"fileUpload": {
"dropzone": {
"selectPrompt": "Haz clic para seleccionar archivos o arrastra y suelta aquí",
"maxSizeLabel": "Tamaño máximo:",
"allowedTypesLabel": "Tipos permitidos:",
"invalidFileType": "Tipo de archivo no válido",
"fileTooLarge": "Archivo demasiado grande",
"fileCounter": "{{current}} de {{max}} archivos",
"maxFilesExceeded": "Máximo de {{max}} archivo(s) permitido",
"noValidFiles": "No se han seleccionado archivos válidos",
"fileActions": {
"play": "Reproducir audio",
"pause": "Pausar audio",
"download": "Descargar archivo",
"remove": "Quitar archivo"
}
},
"fileUploader": {
"allowTypesLabel": "Tipos permitidos:"
}
},
"audioPlayer": {
"trackListTitle": "Pistas",
"trackInfo": {
"title": "Sin título",
"description": "Sin descripción"
}
},
"countdown": {
"days": "Días",
"hours": "Horas",
"minutes": "Minutos",
"seconds": "Segundos"
},
"dualList": {
"searchPlaceHolder": "Buscar"
},
"combobox": {
"searchPlaceholder": "Buscar",
"placeholder": "Seleccione",
"noResultsFound": "No se encontraron resultados",
"clearAll": "Limpiar Todo",
"clearSelection": "Limpiar selección",
"searchOptions": "Buscar opciones",
"loading": "Cargando..."
},
"select": {
"placeholder": "Seleccione"
},
"formErrors": {
"validation": {
"required": "*Este campo es obligatorio",
"email": "*Por favor ingresa una dirección de correo válida",
"minLength": "*Debe tener al menos {{min}} caracteres",
"maxLength": "*No debe tener más de {{max}} caracteres",
"min": "*El valor debe ser al menos {{min}}",
"max": "*El valor no debe superar {{max}}",
"pattern": "*Formato inválido",
"unhandledError": "*Error inesperado"
}
},
"textarea": {
"maxCharacters": "{{current}} de {{max}} caracteres"
},
"table": {
"entriesByPage": "Entradas por página",
"perPage": "{{count}} / página",
"totalEntries": "{{total}} entradas",
"entriesRange": "{{range}} de {{total}} entradas",
"emptyListMessage": "No hay elementos para mostrar"
},
"dataTable": {
"entriesByPage": "Entradas por página",
"perPage": "{{count}} / página",
"totalEntries": "{{total}} entradas",
"entriesRange": "{{range}} de {{total}} entradas",
"emptyListMessage": "No hay elementos para mostrar",
"noData": {
"title": "No hay datos disponibles",
"message": "No hay registros para mostrar en este momento."
},
"noResults": {
"title": "No se encontraron resultados",
"message": "Intenta ajustar tus criterios de búsqueda"
}
},
"wizard": {
"wizardMarker": {
"completed": "Completado",
"inProgress": "En progreso",
"pending": "Pendiente"
},
"wizardWrapper": {
"back": "Atrás",
"previous": "Anterior",
"end": "Finalizar",
"next": "Siguiente",
"step": "Paso {{index}}"
}
},
"datePicker": {
"quickActions": {
"title": "Selección Rápida",
"lastHour": "Última hora",
"last3Hours": "Últimas 3 horas",
"last6Hours": "Últimas 6 horas",
"last12Hours": "Últimas 12 horas",
"last24Hours": "Últimas 24 horas",
"last7Days": "Últimos 7 días",
"last30Days": "Últimos 30 días",
"last6Months": "Últimos 6 meses",
"lastYear": "Último año",
"clear": "Limpiar"
},
"labels": {
"from": "Desde",
"to": "Hasta"
}
}
}
}
```
**Portuguese (`/assets/i18n/pt.json`):**
```json
{
"sdk": {
"fileUpload": {
"dropzone": {
"selectPrompt": "Haz clic para seleccionar archivos o arrastra y suelta aquí",
"maxSizeLabel": "Tamaño máximo:",
"allowedTypesLabel": "Tipos permitidos:",
"invalidFileType": "Tipo de archivo no válido",
"fileTooLarge": "Archivo demasiado grande",
"fileCounter": "{{current}} de {{max}} archivos",
"maxFilesExceeded": "Máximo de {{max}} archivo(s) permitido",
"noValidFiles": "No se han seleccionado archivos válidos",
"fileActions": {
"play": "Reproducir audio",
"pause": "Pausar audio",
"download": "Descargar archivo",
"remove": "Quitar archivo"
}
},
"fileUploader": {
"allowedTypesLabel": "Tipos permitidos:"
}
},
"audioPlayer": {
"trackListTitle": "Trilhas",
"trackInfo": {
"title": "Sem título",
"description": "Sem descrição"
}
},
"countdown": {
"days": "Dias",
"hours": "Horas",
"minutes": "Minutos",
"seconds": "Segundos"
},
"dualList": {
"searchPlaceHolder": "Pesquisar"
},
"combobox": {
"searchPlaceholder": "Pesquisar",
"placeholder": "Selecione",
"noResultsFound": "Nenhum resultado encontrado",
"clearAll": "Limpar Tudo",
"clearSelection": "Limpar seleção",
"searchOptions": "Pesquisar opções",
"loading": "Carregando..."
},
"select": {
"placeholder": "Selecione"
},
"formErrors": {
"validation": {
"required": "*Este campo é obrigatório",
"email": "*Por favor, insira um endereço de e-mail válido",
"minLength": "*Deve ter pelo menos {{min}} caracteres",
"maxLength": "*Deve ter no máximo {{max}} caracteres",
"min": "*O valor deve ser de pelo menos {{min}}",
"max": "*O valor deve ser de no máximo {{max}}",
"pattern": "*Formato inválido",
"unhandledError": "*Erro não tratado"
}
},
"textarea": {
"maxCharacters": "{{current}} de {{max}} caracteres"
},
"table": {
"entriesByPage": "Entradas por página",
"perPage": "{{count}} / página",
"totalEntries": "{{total}} entradas",
"entriesRange": "{{range}} de {{total}} entradas",
"emptyListMessage": "Nenhum item para mostrar"
},
"dataTable": {
"entriesByPage": "Entradas por página",
"perPage": "{{count}} / página",
"totalEntries": "{{total}} entradas",
"entriesRange": "{{range}} de {{total}} entradas",
"emptyListMessage": "Nenhum item para mostrar",
"noData": {
"title": "Nenhum dado disponível",
"message": "Não há registros para exibir neste momento."
},
"noResults": {
"title": "Nenhum resultado encontrado",
"message": "Tente ajustar seus critérios de pesquisa"
}
},
"wizard": {
"wizardMarker": {
"completed": "Concluído",
"inProgress": "Em andamento",
"pending": "Pendente"
},
"wizardWrapper": {
"back": "Voltar",
"previous": "Anterior",
"end": "Fim",
"next": "Próximo",
"step": "Etapa {{index}}"
}
},
"datePicker": {
"quickActions": {
"title": "Seleção Rápida",
"lastHour": "Última hora",
"last3Hours": "Últimas 3 horas",
"last6Hours": "Últimas 6 horas",
"last12Hours": "Últimas 12 horas",
"last24Hours": "Últimas 24 horas",
"last7Days": "Últimos 7 dias",
"last30Days": "Últimos 30 dias",
"last6Months": "Últimos 6 meses",
"lastYear": "Último ano",
"clear": "Limpar"
},
"labels": {
"from": "De",
"to": "Até"
}
}
}
}
```
### 3. Access Language Functionality in Components
The TranslationService automatically loads available languages from `translation.json`:
```typescript
// In any component
import { TranslationService } from '@sixbell-telco/sdk/utils/translation';
import { inject } from '@angular/core';
export class MyComponent {
private translationService = inject(TranslationService);
availableLanguages = this.translationService.getAvailableLanguageCodes();
currentLanguage = this.translationService.currentLanguage;
setLanguage(languageCode: string) {
this.translationService.setLanguage(languageCode);
}
getLanguageName(languageCode: string): string {
return this.translationService.getLanguageDisplayName(languageCode);
}
}
```
### 4. Use Translations in Templates
Translations are automatically loaded and available through the `translate` pipe:
```html
<!-- Access any translation key -->
<h1>{{ 'sdk.language.languages.en' | translate }}</h1>
<!-- With parameters -->
<p>{{ 'welcome.message' | translate: { name: userName } }}</p>
<!-- In component -->
<select (change)="setLanguage($event.target.value)">
@for (lang of availableLanguages; track lang) {
<option [value]="lang">{{ getLanguageName(lang) }}</option>
}
</select>
```
### 5. Add Custom Application Translations
Extend the translation files with your application-specific keys:
**English (`/assets/i18n/en.json`):**
```json
{
"app": {
"title": "My Application",
"welcome": "Welcome to our app",
"features": {
"description": "Powerful features for your business"
}
},
"sdk": {
...// SDK translations
}
}
```
Your application is now configured with full multi-language support. Language preferences are automatically persisted and restored on return visits.
## Usage Examples
### Using Components
Here's a basic example of using a button component:
```typescript
// app.component.ts
import { ButtonComponent } from '@sixbell-telco/sdk/components/button';
@Component({
imports: [ButtonComponent],
template: `
<div>
<h1>Awesome button</h1>
<st-button variant="primary">Click me!</st-button>
</div>
`
})
```
### Using Services in Components
```typescript
// component.ts
import { ThemeService } from '@sixbell-telco/sdk/utils/theme';
import { TranslationService } from '@sixbell-telco/sdk/utils/translation';
@Component({
template: `
<div [class]="themeService.finalTheme()">
<h1>{{ 'welcome.title' | translate }}</h1>
<p>Current theme: {{ themeService.selectedTheme() }}</p>
<p>Dark mode: {{ themeService.isDarkTheme() ? 'Yes' : 'No' }}</p>
<!-- Theme selector -->
<select (change)="changeTheme($event.target.value)">
@for (theme of themeService.getAvailableThemes(); track theme) {
<option [value]="theme">{{ theme }}</option>
}
</select>
<!-- Language selector -->
<select (change)="changeLanguage($event.target.value)">
@for (lang of translationService.getAvailableLanguageCodes(); track lang) {
<option [value]="lang">{{ translationService.getLanguageDisplayName(lang) }}</option>
}
</select>
</div>
`,
})
export class MyComponent {
themeService = inject(ThemeService);
translationService = inject(TranslationService);
changeTheme(theme: string) {
this.themeService.setTheme(theme);
}
changeLanguage(language: string) {
this.translationService.setLanguage(language);
}
}
```
## Quick Start
### Using Components
```typescript
import { Component } from '@angular/core';
import { ButtonComponent } from '@sixbell-telco/sdk/components/button';
import { CardComponent } from '@sixbell-telco/sdk/components/card';
@Component({
selector: 'app-example',
standalone: true,
imports: [ButtonComponent, CardComponent],
template: `
<st-card>
<h2>Hello World</h2>
<st-button variant="primary">Click me!</st-button>
</st-card>
`,
})
export class ExampleComponent {}
```
### Using Form Components
```typescript
import { Component, signal } from '@angular/core';
import { ReactiveFormsModule, FormControl, FormGroup } from '@angular/forms';
import { InputComponent } from '@sixbell-telco/sdk/components/forms/input';
import { ButtonComponent } from '@sixbell-telco/sdk/components/button';
@Component({
selector: 'app-form-example',
standalone: true,
imports: [InputComponent, ButtonComponent, ReactiveFormsModule],
template: `
<form [formGroup]="form">
<st-input formControlName="email" placeholder="Enter email"></st-input>
<st-button (click)="submit()">Submit</st-button>
</form>
`,
})
export class FormExampleComponent {
form = new FormGroup({
email: new FormControl(''),
});
submit() {
console.log(this.form.value);
}
}
```
### Using Services
```typescript
import { Component, inject, effect } from '@angular/core';
import { ThemeService } from '@sixbell-telco/sdk/utils/theme';
import { TranslationService } from '@sixbell-telco/sdk/utils/translation';
import { LoggerService } from '@sixbell-telco/sdk/utils/logger';
@Component({
selector: 'app-services-example',
template: `
<div>
<p>Current Theme: {{ themeService.selectedTheme() }}</p>
<p>Dark Mode: {{ themeService.isDarkTheme() ? 'Yes' : 'No' }}</p>
<button (click)="toggleTheme()">Toggle Theme</button>
</div>
`,
})
export class ServicesExampleComponent {
themeService = inject(ThemeService);
translationService = inject(TranslationService);
logger = inject(LoggerService);
constructor() {
effect(() => {
this.logger.info(`Theme changed to: ${this.themeService.selectedTheme()}`);
});
}
toggleTheme() {
const newScheme = this.themeService.isDarkTheme() ? 'light' : 'dark';
this.themeService.setScheme(newScheme);
}
}
```
## Configuration
### Theme Configuration
Runtime themes are loaded from `themes.json`. See [Theme Service README](utils/theme/) for detailed configuration.
### Translation Configuration
Runtime translations are loaded from `translation.json`. See [Translation Service README](utils/translation/) for detailed configuration.
### Logger Configuration
Configure logging levels and output. See [Logger Service README](utils/logger/) for detailed options.
## Architecture
### Multi-Entry Point Imports
Always use specific imports for optimal tree-shaking:
```typescript
// ✅ Correct - specific imports
import { ButtonComponent } from '@sixbell-telco/sdk/components/button';
import { ThemeService } from '@sixbell-telco/sdk/utils/theme';
// ❌ Avoid - barrel exports
import { ButtonComponent } from '@sixbell-telco/sdk';
```
### Component Prefix
All SDK components use the `st-` prefix:
```html
<st-button>Button</st-button>
<st-input type="text" />
<st-card>Card Content</st-card>
```
### Signal-Based API
Components use Angular 19 signals for reactive inputs:
```typescript
variant = input<'primary' | 'secondary'>();
isDisabled = input(false);
@Component({
template: `<button [disabled]="isDisabled()">{{ variant() }}</button>`,
})
```
## Testing
The SDK includes Jest configuration. Run tests with:
```bash
npm test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # Coverage report
```
See `.github/instructions/testing-basics.instructions.md` for Angular 19 testing patterns.
## Documentation
- **Component Stories**: View component documentation in [Storybook](../storybook/README.md)
- **Live Examples**: Showcase app at `projects/showcase/`
- **API Documentation**: JSDoc comments in component files
- **Changelog**: See [CHANGELOG.md](./CHANGELOG.md)
## Contributing
When creating new components:
1. Use `st-` prefix for selectors
2. Follow CVA pattern for styling variants
3. Use signal-based inputs
4. Add comprehensive JSDoc comments
5. Create Storybook stories
6. Add unit tests with Jest
7. Update CHANGELOG.md
## Resources
- <a href="https://angular.dev" target="_blank" rel="noopener noreferrer">Angular Documentation</a>
- <a href="https://tailwindcss.com" target="_blank" rel="noopener noreferrer">Tailwind CSS</a>
- <a href="https://daisyui.com" target="_blank" rel="noopener noreferrer">DaisyUI</a>
- <a href="https://cva.style" target="_blank" rel="noopener noreferrer">class-variance-authority</a>
- <a href="https://ng-icons.herokuapp.com" target="_blank" rel="noopener noreferrer">ng-icons</a>
- <a href="https://material.angular.io/cdk" target="_blank" rel="noopener noreferrer">Angular CDK</a>
## License
MIT - See [LICENSE](./LICENSE) file for details
## Support
For issues, questions, or feature requests, please visit the project repository or contact the Sixbell Telco team.
---
**Last updated**: November 24, 2025