diff --git a/docs/fundamentals/styles/borders.md b/docs/fundamentals/styles/borders.md index f087c047b9..eec8c4fb89 100644 --- a/docs/fundamentals/styles/borders.md +++ b/docs/fundamentals/styles/borders.md @@ -50,8 +50,27 @@ Customize the radius using the following utils: > **Note:** Since `rounded-2` is the default shape for _Element_, it is possible to use the shorthand `rounded` CSS class. +## AI gradient borders + +Add a 1px gradient border to any element using the AI border utility classes. +The gradient border is rendered via a masked pseudo-element and works with both opaque and transparent backgrounds. + +| Class | Description | +| ----------------------- | ------------------------------------------ | +| `.border-horizontal-ai` | Horizontal (left-to-right) gradient border | +| `.border-vertical-ai` | Vertical (top-to-bottom) gradient border | + +The element must have a `border-radius` set for the gradient to follow the rounded shape. + +```html +AI generated +
...
+``` + ## Examples + + diff --git a/playwright/e2e/element-examples/static.spec.ts b/playwright/e2e/element-examples/static.spec.ts index 621ee716aa..42db316656 100644 --- a/playwright/e2e/element-examples/static.spec.ts +++ b/playwright/e2e/element-examples/static.spec.ts @@ -4,6 +4,7 @@ */ import { test } from '../../support/test-helpers'; +test('ai-border/ai-border', ({ si }) => si.static()); test('badges/badges', ({ si }) => si.static()); test('buttons/buttons', ({ si }) => si.static()); test('buttons/button-groups', ({ si }) => si.static()); diff --git a/playwright/snapshots/static.spec.ts-snapshots/ai-border--ai-border-element-examples-chromium-dark-linux.png b/playwright/snapshots/static.spec.ts-snapshots/ai-border--ai-border-element-examples-chromium-dark-linux.png new file mode 100644 index 0000000000..72b36b6b5c --- /dev/null +++ b/playwright/snapshots/static.spec.ts-snapshots/ai-border--ai-border-element-examples-chromium-dark-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:521191c19207888ef6773f394403f0bb2d1bb4d5cfeb91afbd38c8397098018b +size 10570 diff --git a/playwright/snapshots/static.spec.ts-snapshots/ai-border--ai-border-element-examples-chromium-light-linux.png b/playwright/snapshots/static.spec.ts-snapshots/ai-border--ai-border-element-examples-chromium-light-linux.png new file mode 100644 index 0000000000..eca003661f --- /dev/null +++ b/playwright/snapshots/static.spec.ts-snapshots/ai-border--ai-border-element-examples-chromium-light-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a173aab16b86fd7b6266a70b2c1421c2f61a0cef349e656e0a3c8e420f865b9e +size 9901 diff --git a/playwright/snapshots/static.spec.ts-snapshots/ai-border--ai-border.yaml b/playwright/snapshots/static.spec.ts-snapshots/ai-border--ai-border.yaml new file mode 100644 index 0000000000..835ec54762 --- /dev/null +++ b/playwright/snapshots/static.spec.ts-snapshots/ai-border--ai-border.yaml @@ -0,0 +1,2 @@ +- text: AI generated AI insights +- paragraph: AI-generated content with a vertical gradient border \ No newline at end of file diff --git a/projects/element-theme/src/styles/bootstrap/_utilities.scss b/projects/element-theme/src/styles/bootstrap/_utilities.scss index a6a9f1aacf..0623a0e0b1 100644 --- a/projects/element-theme/src/styles/bootstrap/_utilities.scss +++ b/projects/element-theme/src/styles/bootstrap/_utilities.scss @@ -105,3 +105,46 @@ $status-colors: ( color: #{$value} !important; // stylelint-disable-line declaration-no-important } } + +// AI gradient border utilities. +// Two filled mask layers with `exclude` compositing subtract the inner area, +// leaving only a 1px border ring visible. Works with transparent backgrounds. +@mixin border-ai($angle) { + position: relative; + + &::before { + content: ''; + position: absolute; + inset: 0; + border-radius: inherit; + background: linear-gradient( + $angle, + #{semantic-tokens.$element-base-1-selected} -6.48%, + #{semantic-tokens.$element-base-1-hover} -0.82%, + #{semantic-tokens.$element-ui-0} 49.58%, + #{semantic-tokens.$element-base-1-hover} 101.07%, + #{semantic-tokens.$element-base-1-selected} 106.73% + ); + mask-image: + linear-gradient( + #{semantic-tokens.$element-text-primary}, + #{semantic-tokens.$element-text-primary} + ), + linear-gradient( + #{semantic-tokens.$element-text-primary}, + #{semantic-tokens.$element-text-primary} + ); + mask-clip: border-box, content-box; + mask-composite: exclude; + padding: 1px; + pointer-events: none; + } +} + +.border-horizontal-ai { + @include border-ai(90deg); +} + +.border-vertical-ai { + @include border-ai(180deg); +} diff --git a/src/app/examples/ai-border/ai-border.html b/src/app/examples/ai-border/ai-border.html new file mode 100644 index 0000000000..0031e9cc4d --- /dev/null +++ b/src/app/examples/ai-border/ai-border.html @@ -0,0 +1,8 @@ +
+ AI generated +
+
+ +

AI-generated content with a vertical gradient border

+
+
diff --git a/src/app/examples/ai-border/ai-border.ts b/src/app/examples/ai-border/ai-border.ts new file mode 100644 index 0000000000..eef2d1be2f --- /dev/null +++ b/src/app/examples/ai-border/ai-border.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) Siemens 2016 - 2026 + * SPDX-License-Identifier: MIT + */ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { SiCardComponent } from '@siemens/element-ng/card'; + +@Component({ + selector: 'app-sample', + imports: [SiCardComponent], + templateUrl: './ai-border.html', + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + class: 'p-5 bg-base-1' + } +}) +export class SampleComponent {}