diff --git a/.cursor/rules/angular-components.mdc b/.cursor/rules/angular-components.mdc new file mode 100644 index 000000000..ab6c2ab83 --- /dev/null +++ b/.cursor/rules/angular-components.mdc @@ -0,0 +1,70 @@ +--- +description: Angular component authoring rules for Ion Design System. +globs: projects/ion/src/lib/**/*.component.ts, projects/ion/src/lib/**/*.directive.ts +alwaysApply: false +--- + +# Angular Component & Directive Rules + +## Component Decorator + +- Set `changeDetection: ChangeDetectionStrategy.OnPush` in every `@Component` +- Do NOT set `standalone: true` — it's default in Angular v21+ +- Use `templateUrl` and `styleUrls` for components with more than a few lines of template +- Use inline `template` only for very small components (< ~10 lines of HTML) +- Use relative paths for templateUrl/styleUrls: `'./button.component.html'` + +## Inputs & Outputs + +- Use `input()` signal function instead of `@Input()` decorator +- Use `output()` signal function instead of `@Output()` decorator +- Type inputs explicitly: `label = input()` +- Provide defaults where sensible: `type = input('primary')` +- Use `input.required()` when the value must be provided + +## State Management + +- Use `signal()` for mutable component state +- Use `computed()` for derived state +- Use `effect()` for reactions to signal changes +- Update signals with `.set()` or `.update()` — NEVER use `.mutate()` + +## Host Bindings + +- Do NOT use `@HostBinding` or `@HostListener` decorators +- Use the `host` property in the decorator instead: + +```typescript +@Component({ + host: { + '[attr.disabled]': 'disabled() ? true : null', + '(click)': 'onClick()', + }, +}) +``` + +## Templates + +- Use native control flow: `@if`, `@for`, `@switch` — NEVER `*ngIf`, `*ngFor`, `*ngSwitch` +- Use `[class.name]` bindings instead of `ngClass` +- Use `[style.prop]` bindings instead of `ngStyle` +- Use `[attr.data-testid]` for test selectors following pattern: `'btn-' + (label() || id())` +- Do NOT write arrow functions in templates +- Do NOT call `new Date()` or other globals directly in templates + +## Forms + +- Prefer Reactive Forms over Template-driven forms +- Import `ReactiveFormsModule` or individual form directives as needed + +## Accessibility + +- Must pass all AXE checks and WCAG AA requirements +- Include proper ARIA attributes where semantics are insufficient +- Manage focus for overlays, modals, dropdowns, and tooltips + +## Services + +- Use `providedIn: 'root'` for singleton services +- Use `inject()` function instead of constructor injection +- Design services around a single responsibility diff --git a/.cursor/rules/ion-project.mdc b/.cursor/rules/ion-project.mdc new file mode 100644 index 000000000..651339ad8 --- /dev/null +++ b/.cursor/rules/ion-project.mdc @@ -0,0 +1,63 @@ +--- +description: Ion Design System - project context and conventions. Always active for all files in this repository. +globs: +alwaysApply: true +--- + +# Ion Design System — Project Context + +You are working on **Ion**, the official Angular-based Design System for **Brisanet**. +This is a **library workspace** (`projectType: "library"`) published as `@brisanet/ion` on npm. + +## Tech Stack + +- **Angular** v21 (standalone components are the default — do NOT set `standalone: true`) +- **TypeScript** 5.9 with strict mode +- **SCSS** for component styles with a theme system under `projects/ion/src/styles/` +- **Angular CDK** (`@angular/cdk`) for overlays, portals, and scroll strategies +- **ng-packagr** for library builds +- **Jest** 30 + `jest-preset-angular` for unit testing +- **Angular Testing Library** (`@testing-library/angular`) for integration-style tests +- **Storybook** 10 with `@storybook/angular` for component documentation +- **Prettier** (single quotes, auto end-of-line) +- **EditorConfig** (2-space indent, UTF-8) + +## Project Structure + +``` +projects/ + ion/ # The core library + src/ + lib/ # All component directories + / # One folder per component + .component.ts + .component.html + .component.scss + .component.spec.ts + _.theme.scss # Optional theme file + core/ + types/ # Shared TypeScript interfaces/types + bn-filter/ # Business components prefixed `bn-` + utils/ # Shared utility functions + styles/ # Global design tokens (colors, fonts, shadows, z-indexes, themes) + stories/ # Storybook stories + public-api.ts # Library barrel file — all public exports + ng-package.json + ion-test-app/ # Showcase / integration test app +``` + +## Key Conventions + +- All components are **standalone** (do NOT add `standalone: true` — it's default in Angular v21+) +- Component selector prefix: `ion-` (e.g. `ion-button`, `ion-card`) +- Component class naming: `IonComponent` (e.g. `IonButtonComponent`) +- Service class naming: `IonService` or descriptive name (e.g. `IonModalService`, `TooltipService`) +- Directive class naming: `IonDirective` (e.g. `IonTooltipDirective`) +- Type definitions live in `projects/ion/src/lib/core/types/.ts` +- Every new public component/directive/service MUST be exported from `projects/ion/src/public-api.ts` + +## CI/CD + +- **PR tests**: GitHub Actions runs `npm test` + `npm run build ion` on every PR to `main` +- **Release**: Triggered on GitHub Release publish; builds and publishes to npm with provenance +- **Node version**: 22.22.0 for builds diff --git a/.cursor/rules/storybook.mdc b/.cursor/rules/storybook.mdc new file mode 100644 index 000000000..cd632e64d --- /dev/null +++ b/.cursor/rules/storybook.mdc @@ -0,0 +1,66 @@ +--- +description: Storybook story authoring conventions for Ion components. +globs: projects/ion/src/stories/**/*.stories.ts, projects/ion/**/*.stories.ts +alwaysApply: false +--- + +# Storybook Rules + +## Framework + +- **Storybook 10** with `@storybook/angular` +- Stories live in `projects/ion/src/stories/` or alongside components + +## Story Format + +Use CSF3 (Component Story Format 3) with `Meta` and `StoryObj`: + +```typescript +import type { Meta, StoryObj } from '@storybook/angular'; +import { IonMyComponent } from '../lib/my/my.component'; + +const meta: Meta = { + title: 'Components/MyComponent', + component: IonMyComponent, + tags: ['autodocs'], + argTypes: { + ionOnClick: { action: 'clicked' }, + }, +}; + +export default meta; + +export const Default: StoryObj = { + args: { + label: 'Click me', + type: 'primary', + }, +}; + +export const Disabled: StoryObj = { + args: { + label: 'Disabled', + disabled: true, + }, +}; +``` + +## Providing Services + +If the component depends on services, use `applicationConfig`: + +```typescript +render: (args) => ({ + props: args, + applicationConfig: { + providers: [MyService], + }, +}), +``` + +## Running Storybook + +```bash +npm run storybook # Start dev server on port 6006 +npm run build-storybook # Build static site to dist/storybook/ion +``` diff --git a/.cursor/rules/styling.mdc b/.cursor/rules/styling.mdc new file mode 100644 index 000000000..1309ae776 --- /dev/null +++ b/.cursor/rules/styling.mdc @@ -0,0 +1,40 @@ +--- +description: SCSS styling conventions and design tokens for Ion. +globs: projects/ion/**/*.scss +alwaysApply: false +--- + +# Styling Rules + +## Language + +- Use **SCSS** for all component styles +- Component styles: `.component.scss` (external file, referenced via `styleUrls`) +- Theme files: `_.theme.scss` (partial, imported by the theme system) + +## Design Tokens + +Design tokens are defined under `projects/ion/src/styles/`: + +| Token Category | Location | +| -------------- | ----------------------------- | +| Colors | `styles/colors/colors.scss` | +| Fonts | `styles/fonts/index.scss` | +| Shadows | `styles/shadows/index.scss` | +| Z-indexes | `styles/z-indexes/index.scss` | +| Themes | `styles/themes/index.scss` | +| Overlays | `styles/_overlays.scss` | + +Always use existing design tokens instead of hardcoding values. + +## CSS Class Naming + +- Component variant classes: `ion-btn-primary`, `ion-btn-secondary` +- Size classes: `ion-btn-sm`, `ion-btn-md`, `ion-btn-lg`, `ion-btn-xl` +- State classes: `danger`, `loading`, `right-side-icon` + +## Theming + +- Theme variables are defined in `styles/themes/` +- Components should use CSS custom properties (variables) from the theme +- Support light/dark themes through the existing theme infrastructure diff --git a/.cursor/rules/testing.mdc b/.cursor/rules/testing.mdc new file mode 100644 index 000000000..a45663501 --- /dev/null +++ b/.cursor/rules/testing.mdc @@ -0,0 +1,101 @@ +--- +description: Testing conventions for Ion Design System using Jest and Angular Testing Library. +globs: projects/ion/**/*.spec.ts +alwaysApply: false +--- + +# Testing Rules + +## Framework + +- **Jest 30** with `jest-preset-angular` +- **Angular Testing Library** (`@testing-library/angular`) available for integration-style tests +- **`@testing-library/jest-dom`** matchers are globally available (e.g. `toHaveAttribute`) + +## Test File Location + +- Test files live alongside their component: `.component.spec.ts` +- Test match pattern: `projects/ion/**/*.spec.ts` + +## Test Setup Pattern + +```typescript +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { IonMyComponent } from './my.component'; + +describe('MyComponent', () => { + let component: IonMyComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [IonMyComponent], // standalone component goes in imports + }).compileComponents(); + + fixture = TestBed.createComponent(IonMyComponent); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); +``` + +## Setting Inputs + +- Use `fixture.componentRef.setInput('inputName', value)` — NOT direct property assignment +- Always call `fixture.detectChanges()` after setting inputs + +```typescript +fixture.componentRef.setInput('label', 'Click me'); +fixture.componentRef.setInput('disabled', true); +fixture.detectChanges(); +``` + +## Querying DOM + +- Use `fixture.nativeElement.querySelector()` for DOM queries +- Use `data-testid` attributes for reliable selectors: `[data-testid="btn-myId"]` +- For overlay/portal components (dropdown, modal, tooltip), query from `document.body` + +## Event Testing + +- Use `jest.fn()` for spy functions +- Subscribe to component outputs for event testing +- Call `.click()` on native elements to trigger events + +```typescript +const clickSpy = jest.fn(); +component.ionOnClick.subscribe(clickSpy); +fixture.detectChanges(); + +const button = fixture.nativeElement.querySelector('button'); +button.click(); + +expect(clickSpy).toHaveBeenCalled(); +``` + +## Iteration Tests + +- Use `.forEach()` to test multiple variants (types, sizes, states): + +```typescript +const types = ['primary', 'secondary', 'ghost', 'dashed']; +types.forEach((type) => { + it(`should render type: ${type}`, () => { + fixture.componentRef.setInput('type', type); + fixture.detectChanges(); + const el = fixture.nativeElement.querySelector('button'); + expect(el.classList.contains(`ion-btn-${type}`)).toBe(true); + }); +}); +``` + +## Running Tests + +```bash +npm test # Run all tests +npx jest --testPathPattern=button # Run specific tests +npx jest --coverage # With coverage report +``` diff --git a/.cursor/skills/create-component/SKILL.md b/.cursor/skills/create-component/SKILL.md new file mode 100644 index 000000000..6909dec59 --- /dev/null +++ b/.cursor/skills/create-component/SKILL.md @@ -0,0 +1,123 @@ +--- +name: create-component +description: Step-by-step guide to create a new Ion Design System component with all required files +--- + +# Create a New Ion Component + +Follow these steps to scaffold a new component in the Ion Design System library. + +## 1. Determine the component name + +Ask the user for the component name if not provided. The name should be lowercase and hyphenated (e.g. `progress-bar`, `date-input`). + +## 2. Create the component directory + +Create the directory at `projects/ion/src/lib//`. + +## 3. Create the component TypeScript file + +Create `.component.ts`: + +```typescript +import { ChangeDetectionStrategy, Component, input, output } from '@angular/core'; + +@Component({ + selector: 'ion-', + imports: [], + templateUrl: './.component.html', + styleUrls: ['./.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class IonComponent { + // Define inputs using signal-based input() + // label = input(); + + // Define outputs using output() + // ionOnClick = output(); +} +``` + +**Remember:** + +- Set `changeDetection: ChangeDetectionStrategy.OnPush` +- Use `host: {}` instead of `@HostBinding`/`@HostListener` + +## 4. Create the template file + +Create `.component.html`: + +```html + + + +``` + +## 5. Create the SCSS file + +Create `.component.scss`: + +```scss +// Import shared design tokens as needed +// @use '../../styles/colors/colors' as colors; + +:host { + display: block; +} +``` + +## 6. Create the test file + +Create `.component.spec.ts`: + +## 7. Create the type definitions + +If the component uses custom types, create `projects/ion/src/lib/core/types/.ts`: + +```typescript +export interface Config { + // Define component-specific types here +} +``` + +And export from `projects/ion/src/lib/core/types/index.ts`. + +## 8. Export from public API + +Add the export to `projects/ion/src/public-api.ts`: + +```typescript +export * from './lib//.component'; +``` + +## 9. Verify + +Run the following commands to validate: + +```bash +npm test -- --testPathPattern= +npm run build +``` + +## 10. (Optional) Create a Storybook story + +Create `projects/ion/src/stories/.stories.ts`: + +```typescript +import type { Meta, StoryObj } from '@storybook/angular'; +import { IonComponent } from '../lib//.component'; + +const meta: MetaComponent> = { + title: 'Components/', + component: IonComponent, + tags: ['autodocs'], +}; + +export default meta; + +export const Default: StoryObjComponent> = { + args: { + // Set default args + }, +}; +``` diff --git a/.cursor/skills/create-story/SKILL.md b/.cursor/skills/create-story/SKILL.md new file mode 100644 index 000000000..5e6a02035 --- /dev/null +++ b/.cursor/skills/create-story/SKILL.md @@ -0,0 +1,96 @@ +--- +name: create-story +description: Guide for creating Storybook stories for Ion Design System components +--- + +# Create a Storybook Story + +Follow this guide to create a Storybook story for an Ion component. + +## 1. Identify the component + +Read the component's `.component.ts` to understand all inputs, outputs, and variants. + +## 2. Create the story file + +Create `projects/ion/src/stories/.stories.ts`: + +```typescript +import type { Meta, StoryObj } from '@storybook/angular'; +import { IonComponent } from '../lib//.component'; + +const meta: MetaComponent> = { + title: 'Components/', + component: IonComponent, + tags: ['autodocs'], + argTypes: { + // Map outputs to Storybook actions + ionOnClick: { action: 'clicked' }, + // Configure controls for specific inputs + type: { + control: { type: 'select' }, + options: ['primary', 'secondary', 'ghost', 'dashed'], + }, + size: { + control: { type: 'select' }, + options: ['sm', 'md', 'lg', 'xl'], + }, + }, +}; + +export default meta; +``` + +## 3. Add story variants + +Create a story for each meaningful state of the component: + +```typescript +export const Default: StoryObjComponent> = { + args: { + label: 'Default Button', + type: 'primary', + size: 'md', + }, +}; + +export const Disabled: StoryObjComponent> = { + args: { + label: 'Disabled', + disabled: true, + }, +}; + +export const Loading: StoryObjComponent> = { + args: { + label: 'Loading...', + loading: true, + }, +}; +``` + +## 4. Components with service dependencies + +If the component requires a service, provide it via `applicationConfig`: + +```typescript +import { MyService } from '../lib/my/my.service'; + +const meta: Meta = { + // ... + render: (args) => ({ + props: args, + applicationConfig: { + providers: [MyService], + }, + }), +}; +``` + +## 5. Test the story + +```bash +npm run storybook +``` + +Navigate to `http://localhost:6006` and verify the component renders correctly in all story variants. diff --git a/.cursor/skills/write-tests/SKILL.md b/.cursor/skills/write-tests/SKILL.md new file mode 100644 index 000000000..efd7c7a02 --- /dev/null +++ b/.cursor/skills/write-tests/SKILL.md @@ -0,0 +1,89 @@ +--- +name: write-tests +description: Guide for writing comprehensive tests for Ion Design System components using Jest + Angular Testing Library +--- + +# Write Tests for an Ion Component + +Follow this guide to write comprehensive tests for an existing Ion component. + +## 1. Identify the component + +Determine which component needs tests. Read the component's `.component.ts` to understand: + +- All `input()` signals and their types/defaults +- All `output()` signals +- All public methods +- Template logic (via `.component.html`) +- Component dependencies (imported components) + +## 2. Test file setup + +The test file should be at `projects/ion/src/lib//.component.spec.ts`. + +## 3. Test categories to cover + +### a) Rendering Tests + +- Default rendering without inputs +- Rendering with various input combinations +- Conditional rendering (`@if` blocks) + +### b) Input Variant Tests + +Use iteration when testing multiple values of the same input: + +```typescript +const sizes: Array<'sm' | 'md' | 'lg' | 'xl'> = ['sm', 'md', 'lg', 'xl']; +sizes.forEach((size) => { + it(`should render size: ${size}`, () => { + fixture.componentRef.setInput('size', size); + fixture.detectChanges(); + const el = fixture.nativeElement.querySelector('button'); + expect(el.classList.contains(`ion-btn-${size}`)).toBe(true); + }); +}); +``` + +### c) Event/Output Tests + +```typescript +it('should emit event', () => { + const spy = jest.fn(); + component.ionOnClick.subscribe(spy); + fixture.detectChanges(); + + const el = fixture.nativeElement.querySelector('button'); + el.click(); + + expect(spy).toHaveBeenCalled(); +}); +``` + +### d) State Tests + +- Disabled state prevents interactions +- Loading state shows spinner and blocks events +- Boolean flags toggle CSS classes + +### e) Accessibility Tests + +- Elements have correct ARIA attributes +- Disabled elements are properly marked +- Focus management works correctly + +## 4. Key patterns + +- **Always** use `fixture.componentRef.setInput()` to set signal inputs +- **Always** call `fixture.detectChanges()` after changing inputs +- Use `fixture.nativeElement.querySelector()` for DOM queries +- Use `document.body.querySelector()` for overlay/portal elements (dropdowns, modals, tooltips) +- Use `[data-testid]` attribute selectors for reliable queries +- Use `jest.fn()` for spy/mock functions + +## 5. Run the tests + +```bash +npx jest --testPathPattern= +npx jest --testPathPattern= --coverage +``` diff --git a/README.md b/README.md index 1a7e840d6..d5a90a3ba 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,165 @@ -# IonDs +![Ion Design System](./projects/ion-test-app/public/capa.svg) -This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.0.0. +# Ion Design System -## Development server +Ion is the official **Design System** for **Brisanet**, providing a suite of high-quality components and patterns to ensure consistency, accessibility, and high performance across all our frontend projects. -To start a local development server, run: +Built with **Angular**, Ion leverages modern features like **Signals** and **Standalone Components** to offer a developer-friendly experience and scalable architecture. + +## 📌 Version Support + +We maintain support for multiple Angular versions to ensure compatibility across all internal projects: + +| Branch | Angular Version | Status | +| :----------- | :-------------- | :------------------ | +| `main` | v21 | **Active (Stable)** | +| `support/19` | v19 | Maintenance | +| `support/8` | v8 | Legacy | + +> [!IMPORTANT] +> When starting a new project, always check which version of Angular you are using and pull the corresponding branch. + +## 🚀 Key Features + +- 💎 **Universal Consistency**: Unified design language for the entire organization. +- ⚡ **High Performance**: Optimized with Angular Signals and `ChangeDetectionStrategy.OnPush`. +- 🎨 **Flexible**: Easily customizable themes and styles. +- 📚 **Interactive Documentation**: Integrated with Storybook for component exploration. +- 🛠️ **Robust Testing**: Fully tested using Jest and Angular Testing Library. + +## 📦 Installation + +To use Ion in your project, install the package from our internal registry: ```bash -ng serve +npm install @brisanet/ion ``` -Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files. +## 📖 Usage -## Code scaffolding +Import the components directly into your standalone components: -Angular CLI includes powerful code scaffolding tools. To generate a new component, run: +```typescript +import { IonButtonComponent } from '@brisanet/ion'; -```bash -ng generate component component-name +@Component({ + selector: 'app-my-component', + imports: [IonButtonComponent], + template: ` `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class MyComponent { + handleClick() { + console.log('Button clicked!'); + } +} ``` -For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: +## 🛠️ Development + +### Local Setup + +Clone the repository and install dependencies: ```bash -ng generate --help +git clone https://github.com/Brisanet/ion.git +cd ion +npm install ``` -## Building +### Storybook -To build the project run: +To explore and develop components in isolation: ```bash -ng build +npm run storybook ``` -This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed. - -## Running unit tests +### Testing -To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command: +Run the test suite using Jest: ```bash -ng test +npm test ``` -## Running end-to-end tests +### Building -For end-to-end (e2e) testing, run: +To build the library: ```bash -ng e2e +npm run build ``` -Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. +The build artifacts will be stored in the `dist/ion` directory. + +## 🔄 Maintenance & Synchronization (Cherry-pick) + +To keep all supported versions in sync, especially for bug fixes, we use `git cherry-pick`. + +### How to propagate a change: + +1. **Commit the change to `main` (with PR, obviously)**: + Ensure your change is merged and tested in the `main` branch. Note the **Commit Hash**. + ```bash + git log --oneline + ``` +2. **Switch to the target maintenance branch**: + ```bash + git checkout support/19 + ``` +3. **Apply the change using cherry-pick**: + ```bash + git cherry-pick -x + ``` +4. **Resolve conflicts (if any)**: + Since different Angular versions might have structural differences, conflicts may occur. Resolve them, then: + ```bash + git add . + git cherry-pick --continue + ``` +5. **Push the changes**: + ```bash + git push origin support/19 + ``` + +## 🧱 Project Structure + +- `projects/ion`: The core Design System library. +- `projects/ion-test-app`: A showcase and testing application for validating component integration. + +## 📋 Rules (.cursor/rules/) + +Regras que o Cursor AI segue automaticamente ao trabalhar no projeto. + +| Arquivo | Tipo | Descrição | +| :----------------------- | :------------ | :-------------------------------------------------------------------------------- | +| `ion-project.mdc` | `alwaysApply` | Contexto do projeto: tech stack, estrutura, convenções, CI/CD | +| `angular-components.mdc` | Dinâmica | Padrões de componentes: `input()`, `output()`, signals, `OnPush`, host, templates | +| `testing.mdc` | Dinâmica | Convenções de teste: Jest + Angular Testing Library, `setInput()`, DOM queries | +| `storybook.mdc` | Dinâmica | Padrões CSF3: `Meta`, `StoryObj`, `argTypes`, providers | +| `styling.mdc` | Dinâmica | Design tokens SCSS, naming de classes, temas | + +> **alwaysApply**: sempre ativa. **Dinâmica**: ativa apenas quando o Cursor detecta relevância pelo glob pattern. + +### 🛠️ Skills (.cursor/skills/) + +Workflows passo-a-passo invocáveis via `/create-component`, `/write-tests`, `/create-story`. + +| Skill | Descrição | +| :----------------- | :------------------------------------------------------------------------------------ | +| `create-component` | Scaffold completo: `.ts`, `.html`, `.scss`, `.spec.ts`, types, `public-api.ts`, story | +| `write-tests` | Guia para escrever testes cobrindo rendering, inputs, events, estados, a11y | +| `create-story` | Criação de stories Storybook com variants e providers | + +#### Como usar + +No Cursor IDE, as rules já são carregadas automaticamente. Para as skills, digite `/` no chat e selecione o skill desejado (ex: `/create-component`). + +## 🤝 Contributing + +Ion is a vital organ of Brisanet's frontend ecosystem. Contributions are welcome! Please follow our internal coding standards and ensure all tests pass before submitting a pull request. -## Additional Resources +--- -For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. +Made with ❤️ by the **Brisanet** Frontend Team. diff --git a/projects/ion-test-app/public/capa.svg b/projects/ion-test-app/public/capa.svg new file mode 100644 index 000000000..91b511baf --- /dev/null +++ b/projects/ion-test-app/public/capa.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +