Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
751 changes: 0 additions & 751 deletions .claude/CLAUDE-v1.6.md

This file was deleted.

51 changes: 51 additions & 0 deletions src/lib/components/toast/toast.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Component, Input } from '@angular/core';
import { Toast } from 'primeng/toast';
import { MessageService } from 'primeng/api';
import { SharedModule } from 'primeng/api';

export type ToastSeverity = 'success' | 'info' | 'warn' | 'error' | 'secondary' | 'contrast';
export type ToastPosition =
| 'top-right'
| 'top-left'
| 'top-center'
| 'bottom-right'
| 'bottom-left'
| 'bottom-center'
| 'center';

const SEVERITY_ICONS: Record<string, string> = {
info: 'ti ti-info-circle',
success: 'ti ti-circle-check',
warn: 'ti ti-alert-triangle',
error: 'ti ti-alert-circle',
};

@Component({
selector: 'ui-toast',
standalone: true,
imports: [Toast, SharedModule],
providers: [MessageService],
template: `
<p-toast [position]="position" [key]="key" [life]="life">
<ng-template #message let-message>
<div class="p-toast-accent-line"></div>
<i [class]="resolveIcon(message) + ' p-toast-message-icon'"></i>
<div class="p-toast-message-text">
<span class="p-toast-summary">{{ message.summary }}</span>
@if (message.detail) {
<div class="p-toast-detail">{{ message.detail }}</div>
}
</div>
</ng-template>
</p-toast>
`,
})
export class ToastComponent {
@Input() position: ToastPosition = 'top-right';
@Input() key: string | undefined = undefined;
@Input() life = 5000;

resolveIcon(message: { severity?: string; icon?: string }): string {
return message.icon ?? SEVERITY_ICONS[message.severity ?? 'info'] ?? 'ti ti-info-circle';
}
}
6 changes: 6 additions & 0 deletions src/prime-preset/map-tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import tokens from './tokens/tokens.json';
import { avatarCss } from './tokens/components/avatar';
import { buttonCss } from './tokens/components/button';
import { checkboxCss } from './tokens/components/checkbox';
import { tagCss } from './tokens/components/tag';
import { toastCss } from './tokens/components/toast';
import { tooltipCss } from './tokens/components/tooltip';

const presetTokens: Preset<AuraBaseDesignTokens> = {
Expand All @@ -29,6 +31,10 @@ const presetTokens: Preset<AuraBaseDesignTokens> = {
...(tokens.components.tag as unknown as ComponentsDesignTokens['tag']),
css: tagCss,
},
toast: {
...(tokens.components.toast as unknown as ComponentsDesignTokens['toast']),
css: toastCss,
},
} as ComponentsDesignTokens,
};

Expand Down
144 changes: 144 additions & 0 deletions src/prime-preset/tokens/components/toast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
export const toastCss = ({ dt }: { dt: (token: string) => string }): string => `
/* Основной контейнер toast-сообщения */
.p-toast-message {
width: ${dt('toast.root.width')};
overflow: hidden;
border-width: ${dt('toast.root.borderWidth')};
border-radius: ${dt('toast.root.borderRadius')};
box-shadow: ${dt('toast.colorScheme.light.info.shadow')};
position: relative;
}

/* border-radius для контента toast-сообщения */
.p-toast .p-toast-message .p-toast-message-content {
border-radius: ${dt('toast.root.borderRadius')};
}

/* Текстовый блок toast */
.p-toast-message-text {
flex: 1;
display: flex;
flex-direction: column;
gap: ${dt('toast.text.gap')};
}

/* Заголовок toast */
.p-toast-summary {
font-family: ${dt('fonts.fontFamily.base')};
line-height: ${dt('fonts.lineHeight.250')};
}

/* Детальное описание toast */
.p-toast-message .p-toast-detail {
font-family: ${dt('fonts.fontFamily.base')};
line-height: ${dt('fonts.lineHeight.250')};
}

/* Кнопка закрытия toast-сообщения */
.p-toast-message .p-toast-message-content .p-toast-close-button {
margin: 0;
padding: 0;
right: 0;
}

/* Общие стили border для кнопки закрытия всех типов toast */
.p-toast-message-info .p-toast-close-button,
.p-toast-message-success .p-toast-close-button,
.p-toast-message-warn .p-toast-close-button,
.p-toast-message-error .p-toast-close-button {
border: ${dt('toast.extend.extCloseButton.width')} solid;
}

/* Общие стили для акцентной линии всех типов toast */
.p-toast-message-info .p-toast-accent-line,
.p-toast-message-success .p-toast-accent-line,
.p-toast-message-warn .p-toast-accent-line,
.p-toast-message-error .p-toast-accent-line {
width: ${dt('toast.extend.extAccentLine.width')};
position: absolute;
left: 0;
top: 0;
bottom: 0;
border-radius: ${dt('toast.root.borderRadius')} 0 0 ${dt('toast.root.borderRadius')};
}

/* Стили для toast типа Info */
.p-toast-message-info .p-toast-message-icon {
color: ${dt('toast.extend.extInfo.color')};
}

.p-toast-message-info .p-toast-close-button {
color: ${dt('toast.extend.extInfo.closeButton.color')};
border-color: ${dt('toast.extend.extInfo.closeButton.borderColor')};
}

.p-toast-message.p-toast-message-info .p-toast-close-button.p-button-text:not(:disabled):hover {
background: ${dt('toast.colorScheme.light.info.closeButton.hoverBackground')};
border-color: ${dt('toast.extend.extInfo.closeButton.borderColor')};
color: ${dt('toast.extend.extInfo.closeButton.color')};
}

.p-toast-message-info .p-toast-accent-line {
background: ${dt('toast.extend.extInfo.color')};
}

/* Стили для toast типа Success */
.p-toast-message-success .p-toast-message-icon {
color: ${dt('toast.extend.extSuccess.color')};
}

.p-toast-message-success .p-toast-close-button {
color: ${dt('toast.extend.extSuccess.closeButton.color')};
border-color: ${dt('toast.extend.extSuccess.closeButton.borderColor')};
}

.p-toast-message.p-toast-message-success .p-toast-close-button.p-button-text:not(:disabled):hover {
background: ${dt('toast.colorScheme.light.success.closeButton.hoverBackground')};
border-color: ${dt('toast.extend.extSuccess.closeButton.borderColor')};
color: ${dt('toast.extend.extSuccess.closeButton.color')};
}

.p-toast-message-success .p-toast-accent-line {
background: ${dt('toast.extend.extSuccess.color')};
}

/* Стили для toast типа Warn */
.p-toast-message-warn .p-toast-message-icon {
color: ${dt('toast.extend.extWarn.color')};
}

.p-toast-message-warn .p-toast-close-button {
color: ${dt('toast.extend.extWarn.closeButton.color')};
border-color: ${dt('toast.extend.extWarn.closeButton.borderColor')};
}

.p-toast-message.p-toast-message-warn .p-toast-close-button.p-button-text:not(:disabled):hover {
background: ${dt('toast.colorScheme.light.warn.closeButton.hoverBackground')};
border-color: ${dt('toast.extend.extWarn.closeButton.borderColor')};
color: ${dt('toast.extend.extWarn.closeButton.color')};
}

.p-toast-message-warn .p-toast-accent-line {
background: ${dt('toast.extend.extWarn.color')};
}

/* Стили для toast типа Error */
.p-toast-message-error .p-toast-message-icon {
color: ${dt('toast.extend.extError.color')};
}

.p-toast-message-error .p-toast-close-button {
color: ${dt('toast.extend.extError.closeButton.color')};
border-color: ${dt('toast.extend.extError.closeButton.borderColor')};
}

.p-toast-message.p-toast-message-error .p-toast-close-button.p-button-text:not(:disabled):hover {
background: ${dt('toast.colorScheme.light.error.closeButton.hoverBackground')};
border-color: ${dt('toast.extend.extError.closeButton.borderColor')};
color: ${dt('toast.extend.extError.closeButton.color')};
}

.p-toast-message-error .p-toast-accent-line {
background: ${dt('toast.extend.extError.color')};
}
`;
87 changes: 87 additions & 0 deletions src/stories/components/toast/examples/toast-position.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Component } from '@angular/core';
import { StoryObj } from '@storybook/angular';
import { Toast } from 'primeng/toast';
import { Button } from 'primeng/button';
import { MessageService, SharedModule } from 'primeng/api';

const POSITIONS = [
{ position: 'top-left', label: 'Вверх слева', key: 'pos-top-left' },
{ position: 'top-center', label: 'Вверх по центру', key: 'pos-top-center' },
{ position: 'top-right', label: 'Вверх справа', key: 'pos-top-right' },
{ position: 'bottom-left', label: 'Вниз слева', key: 'pos-bottom-left' },
{ position: 'bottom-center', label: 'Вниз по центру', key: 'pos-bottom-center' },
{ position: 'bottom-right', label: 'Вниз справа', key: 'pos-bottom-right' },
] as const;

const template = `
@for (p of positions; track p.key) {
<p-toast [position]="p.position" [key]="p.key">
<ng-template #message let-message>
<div class="p-toast-accent-line"></div>
<i [class]="message.icon + ' p-toast-message-icon'"></i>
<div class="p-toast-message-text">
<span class="p-toast-summary">{{ message.summary }}</span>
<div class="p-toast-detail">{{ message.detail }}</div>
</div>
</ng-template>
</p-toast>
}

<div class="flex flex-col gap-2 items-center justify-center min-h-48">
@for (p of positions; track p.key) {
<p-button
[label]="p.label"
severity="contrast"
(onClick)="show(p.key, p.position)"
></p-button>
}
</div>
`;
const styles = '';

@Component({
selector: 'app-toast-position',
standalone: true,
imports: [Toast, Button, SharedModule],
providers: [MessageService],
template,
styles,
})
export class ToastPositionComponent {
readonly positions = POSITIONS;

constructor(private readonly messageService: MessageService) {}

show(key: string, position: string): void {
this.messageService.add({
key,
severity: 'info',
summary: 'Сообщение',
detail: 'Позиция: ' + position,
life: 3000,
icon: 'ti ti-info-circle',
});
}
}

export const Position: StoryObj = {
render: () => ({
template: `<app-toast-position></app-toast-position>`,
}),
parameters: {
docs: {
description: { story: 'Расположение тоста задаётся через `position` и `key`.' },
source: {
language: 'ts',
code: `
<p-toast position="top-left" key="top-left"></p-toast>
<p-toast position="top-center" key="top-center"></p-toast>
<p-toast position="top-right" key="top-right"></p-toast>
<p-toast position="bottom-left" key="bottom-left"></p-toast>
<p-toast position="bottom-center" key="bottom-center"></p-toast>
<p-toast position="bottom-right" key="bottom-right"></p-toast>
`,
},
},
},
};
Loading
Loading