mirror of
https://github.com/bitwarden/browser
synced 2025-12-21 02:33:46 +00:00
[PM-25871] updated phishing warning UI (#16748)
* refactor phishing-warning.component * add hideBackground input to anon-layout component * add icon tile component to CL * add storybook story; fix binding bug in template * export icon-tile from CL * update design of phishing warning page * revert icon button to use string type; add comment to icon scss * update callout to allow no icon/title on all variants * update phishing warning styles * fix defects * crowdin messages cannot be changed, they must be replaced * add global css override * add phishing help link * update icon used in tile * tweak styles
This commit is contained in:
7
libs/components/src/icon-tile/icon-tile.component.html
Normal file
7
libs/components/src/icon-tile/icon-tile.component.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<div
|
||||
[ngClass]="containerClasses()"
|
||||
[attr.aria-label]="ariaLabel()"
|
||||
[attr.role]="ariaLabel() ? 'img' : null"
|
||||
>
|
||||
<i [ngClass]="iconClasses()" aria-hidden="true"></i>
|
||||
</div>
|
||||
111
libs/components/src/icon-tile/icon-tile.component.ts
Normal file
111
libs/components/src/icon-tile/icon-tile.component.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { NgClass } from "@angular/common";
|
||||
import { Component, computed, input } from "@angular/core";
|
||||
|
||||
import { BitwardenIcon } from "../shared/icon";
|
||||
|
||||
export type IconTileVariant = "primary" | "success" | "warning" | "danger" | "muted";
|
||||
|
||||
export type IconTileSize = "small" | "default" | "large";
|
||||
|
||||
export type IconTileShape = "square" | "circle";
|
||||
|
||||
const variantStyles: Record<IconTileVariant, string[]> = {
|
||||
primary: ["tw-bg-primary-100", "tw-text-primary-700"],
|
||||
success: ["tw-bg-success-100", "tw-text-success-700"],
|
||||
warning: ["tw-bg-warning-100", "tw-text-warning-700"],
|
||||
danger: ["tw-bg-danger-100", "tw-text-danger-700"],
|
||||
muted: ["tw-bg-secondary-100", "tw-text-secondary-700"],
|
||||
};
|
||||
|
||||
const sizeStyles: Record<IconTileSize, { container: string[]; icon: string[] }> = {
|
||||
small: {
|
||||
container: ["tw-w-6", "tw-h-6"],
|
||||
icon: ["tw-text-sm"],
|
||||
},
|
||||
default: {
|
||||
container: ["tw-w-8", "tw-h-8"],
|
||||
icon: ["tw-text-base"],
|
||||
},
|
||||
large: {
|
||||
container: ["tw-w-10", "tw-h-10"],
|
||||
icon: ["tw-text-lg"],
|
||||
},
|
||||
};
|
||||
|
||||
const shapeStyles: Record<IconTileShape, Record<IconTileSize, string[]>> = {
|
||||
square: {
|
||||
small: ["tw-rounded"],
|
||||
default: ["tw-rounded-md"],
|
||||
large: ["tw-rounded-lg"],
|
||||
},
|
||||
circle: {
|
||||
small: ["tw-rounded-full"],
|
||||
default: ["tw-rounded-full"],
|
||||
large: ["tw-rounded-full"],
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Icon tiles are static containers that display an icon with a colored background.
|
||||
* They are similar to icon buttons but are not interactive and are used for visual
|
||||
* indicators, status representations, or decorative elements.
|
||||
*
|
||||
* Use icon tiles to:
|
||||
* - Display status or category indicators
|
||||
* - Represent different types of content
|
||||
* - Create visual hierarchy in lists or cards
|
||||
* - Show app or service icons in a consistent format
|
||||
*/
|
||||
@Component({
|
||||
selector: "bit-icon-tile",
|
||||
templateUrl: "icon-tile.component.html",
|
||||
imports: [NgClass],
|
||||
})
|
||||
export class IconTileComponent {
|
||||
/**
|
||||
* The BWI icon name
|
||||
*/
|
||||
readonly icon = input.required<BitwardenIcon>();
|
||||
|
||||
/**
|
||||
* The visual theme of the icon tile
|
||||
*/
|
||||
readonly variant = input<IconTileVariant>("primary");
|
||||
|
||||
/**
|
||||
* The size of the icon tile
|
||||
*/
|
||||
readonly size = input<IconTileSize>("default");
|
||||
|
||||
/**
|
||||
* The shape of the icon tile
|
||||
*/
|
||||
readonly shape = input<IconTileShape>("square");
|
||||
|
||||
/**
|
||||
* Optional aria-label for accessibility when the icon has semantic meaning
|
||||
*/
|
||||
readonly ariaLabel = input<string>();
|
||||
|
||||
protected readonly containerClasses = computed(() => {
|
||||
const variant = this.variant();
|
||||
const size = this.size();
|
||||
const shape = this.shape();
|
||||
|
||||
return [
|
||||
"tw-inline-flex",
|
||||
"tw-items-center",
|
||||
"tw-justify-center",
|
||||
"tw-flex-shrink-0",
|
||||
...variantStyles[variant],
|
||||
...sizeStyles[size].container,
|
||||
...shapeStyles[shape][size],
|
||||
];
|
||||
});
|
||||
|
||||
protected readonly iconClasses = computed(() => {
|
||||
const size = this.size();
|
||||
|
||||
return ["bwi", this.icon(), ...sizeStyles[size].icon];
|
||||
});
|
||||
}
|
||||
114
libs/components/src/icon-tile/icon-tile.stories.ts
Normal file
114
libs/components/src/icon-tile/icon-tile.stories.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { Meta, StoryObj } from "@storybook/angular";
|
||||
|
||||
import { BITWARDEN_ICONS } from "../shared/icon";
|
||||
|
||||
import { IconTileComponent } from "./icon-tile.component";
|
||||
|
||||
export default {
|
||||
title: "Component Library/Icon Tile",
|
||||
component: IconTileComponent,
|
||||
args: {
|
||||
icon: "bwi-star",
|
||||
variant: "primary",
|
||||
size: "default",
|
||||
shape: "square",
|
||||
},
|
||||
argTypes: {
|
||||
variant: {
|
||||
options: ["primary", "success", "warning", "danger", "muted"],
|
||||
control: { type: "select" },
|
||||
},
|
||||
size: {
|
||||
options: ["small", "default", "large"],
|
||||
control: { type: "select" },
|
||||
},
|
||||
shape: {
|
||||
options: ["square", "circle"],
|
||||
control: { type: "select" },
|
||||
},
|
||||
icon: {
|
||||
options: BITWARDEN_ICONS,
|
||||
control: { type: "select" },
|
||||
},
|
||||
ariaLabel: {
|
||||
control: { type: "text" },
|
||||
},
|
||||
},
|
||||
parameters: {
|
||||
design: {
|
||||
type: "figma",
|
||||
url: "https://atlassian.design/components/icon/icon-tile/examples",
|
||||
},
|
||||
},
|
||||
} as Meta<IconTileComponent>;
|
||||
|
||||
type Story = StoryObj<IconTileComponent>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
export const AllVariants: Story = {
|
||||
render: () => ({
|
||||
template: `
|
||||
<div class="tw-flex tw-gap-4 tw-items-center tw-flex-wrap">
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2">
|
||||
<bit-icon-tile icon="bwi-collection" variant="primary"></bit-icon-tile>
|
||||
<span class="tw-text-sm tw-text-muted">Primary</span>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2">
|
||||
<bit-icon-tile icon="bwi-check-circle" variant="success"></bit-icon-tile>
|
||||
<span class="tw-text-sm tw-text-muted">Success</span>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2">
|
||||
<bit-icon-tile icon="bwi-exclamation-triangle" variant="warning"></bit-icon-tile>
|
||||
<span class="tw-text-sm tw-text-muted">Warning</span>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2">
|
||||
<bit-icon-tile icon="bwi-error" variant="danger"></bit-icon-tile>
|
||||
<span class="tw-text-sm tw-text-muted">Danger</span>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2">
|
||||
<bit-icon-tile icon="bwi-question-circle" variant="muted"></bit-icon-tile>
|
||||
<span class="tw-text-sm tw-text-muted">Muted</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
}),
|
||||
};
|
||||
|
||||
export const AllSizes: Story = {
|
||||
render: () => ({
|
||||
template: `
|
||||
<div class="tw-flex tw-gap-4 tw-items-center">
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2">
|
||||
<bit-icon-tile icon="bwi-star" variant="primary" size="small"></bit-icon-tile>
|
||||
<span class="tw-text-sm tw-text-muted">Small</span>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2">
|
||||
<bit-icon-tile icon="bwi-star" variant="primary" size="default"></bit-icon-tile>
|
||||
<span class="tw-text-sm tw-text-muted">Default</span>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2">
|
||||
<bit-icon-tile icon="bwi-star" variant="primary" size="large"></bit-icon-tile>
|
||||
<span class="tw-text-sm tw-text-muted">Large</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
}),
|
||||
};
|
||||
|
||||
export const AllShapes: Story = {
|
||||
render: () => ({
|
||||
template: `
|
||||
<div class="tw-flex tw-gap-4 tw-items-center">
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2">
|
||||
<bit-icon-tile icon="bwi-user" variant="primary" shape="square"></bit-icon-tile>
|
||||
<span class="tw-text-sm tw-text-muted">Square</span>
|
||||
</div>
|
||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2">
|
||||
<bit-icon-tile icon="bwi-user" variant="primary" shape="circle"></bit-icon-tile>
|
||||
<span class="tw-text-sm tw-text-muted">Circle</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
}),
|
||||
};
|
||||
1
libs/components/src/icon-tile/index.ts
Normal file
1
libs/components/src/icon-tile/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./icon-tile.component";
|
||||
Reference in New Issue
Block a user