feat:generic Badge(0.3.0)

This commit is contained in:
Тимур Городецкий
2026-08-14 12:06:07 +05:00
parent c72f93e359
commit d16e4a2216
6 changed files with 114 additions and 1 deletions
+17
View File
@@ -118,6 +118,23 @@ Tabs (из CategoryTabs), Breadcrumbs (новый), Sidebar (из SideNav), AppL
Drawer(?). Сначала «расцепить» от роутинга портала → сделать controlled Drawer(?). Сначала «расцепить» от роутинга портала → сделать controlled
(items + activeId + onSelect), потом переносить. Даёт новым приложениям готовую оболочку. (items + activeId + onSelect), потом переносить. Даёт новым приложениям готовую оболочку.
### Миграция request-portal (в процессе)
- [СДЕЛАНО] Формы переведены на пакет через переключение barrel shared/ui/index.ts
(перенесённые компоненты реэкспортятся из @tnsu/ui-kit). FormMode объединён на пакетный.
- [СДЕЛАНО] Чистка: 12 прямых импортеров (SideNav, табы, Drawer, RequestGrid, пикеры,
unsavedChanges, RequestPortal→IconSprite, ItemsTable, SubmitActions) → @tnsu/ui-kit;
удалены 20 локальных папок-дублей. В shared/ui осталось: ItemsTable, PeopleField,
SubmitActions, ErrorOverlay, InitiatorLine (+useRequestSubmit, index). Heft собирается.
- [СДЕЛАНО] B: локальный components/SideNav заменён на пакетный Sidebar + SidebarToggle.
В RequestPortal: navItems (с counts), состояние mobileNavOpen, бургер в шапке main
(.mobileNav, виден < 768px). Shell CSS: убран старый перелом 900px; на < 768 .side
схлопывается (drawer position:fixed), main на всю ширину. SideNav удалён. Heft ок.
### Badge (0.3.0) — паттерн «презентация в kit, смысл в проекте»
Generic Badge в kit (variant: neutral/muted/info/success/warning/danger/primary). Портальный
StatusBadge переписан в тонкий маппер REQUEST_STATUS→variant поверх Badge; StatusBadge.module.scss
удалён. Это шаблон для будущего разделения пикеров (group 3): вид в kit, привязка к данным в проекте.
### Порядок работ ### Порядок работ
1. [СДЕЛАНО в 0.1.0] Быстрая пачка (20 компонентов): вся Группа 1 (кроме ErrorOverlay/ 1. [СДЕЛАНО в 0.1.0] Быстрая пачка (20 компонентов): вся Группа 1 (кроме ErrorOverlay/
StatusBadge — оказались связаны с diagnostics/statuses, отложены) + ConfirmDialog/ StatusBadge — оказались связаны с diagnostics/statuses, отложены) + ConfirmDialog/
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@tnsu/ui-kit", "name": "@tnsu/ui-kit",
"version": "0.2.0", "version": "0.3.0",
"description": "TNSU shared UI components for SPFx web parts", "description": "TNSU shared UI components for SPFx web parts",
"author": "Timur Gorodetskiy", "author": "Timur Gorodetskiy",
"license": "ISC", "license": "ISC",
+29
View File
@@ -0,0 +1,29 @@
@import '../tokens/tokens';
.badge {
display: inline-flex;
align-items: center;
padding: 5px 12px;
border-radius: $r-sm;
font-family: $font-sans;
font-size: 12.5px;
font-weight: 600;
letter-spacing: .2px;
white-space: nowrap;
}
// Компактный вариант — для ячейки таблицы.
.sm {
padding: 3px 10px;
border-radius: $r-md;
font-size: $fs-caption;
letter-spacing: normal;
}
.neutral { background: $gray-100; color: $gray-700; }
.muted { background: $gray-100; color: $gray-500; }
.info { background: $blue-50; color: $blue-600; }
.success { background: $green-50; color: $green-600; }
.warning { background: $gold-50; color: $amber-700; }
.danger { background: $red-50; color: $red-500; }
.primary { background: $navy-50; color: $navy-800; }
+35
View File
@@ -0,0 +1,35 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { Badge } from './Badge';
const meta: Meta<typeof Badge> = {
title: 'Сообщения/Badge',
component: Badge,
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['neutral', 'muted', 'info', 'success', 'warning', 'danger', 'primary']
},
size: { control: 'radio', options: ['sm', 'md'] }
},
args: { variant: 'info', size: 'md', children: 'На согласовании' }
};
export default meta;
type Story = StoryObj<typeof Badge>;
export const Info: Story = {};
export const AllVariants: Story = {
render: () => (
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
<Badge variant="neutral">Черновик</Badge>
<Badge variant="muted">В очереди</Badge>
<Badge variant="info">На согласовании</Badge>
<Badge variant="success">Согласовано</Badge>
<Badge variant="warning">Возвращена</Badge>
<Badge variant="danger">Отклонена</Badge>
<Badge variant="primary">На исполнении</Badge>
</div>
)
};
+30
View File
@@ -0,0 +1,30 @@
import * as React from 'react';
import styles from './Badge.module.scss';
export type BadgeVariant = 'neutral' | 'muted' | 'info' | 'success' | 'warning' | 'danger' | 'primary';
export interface IBadgeProps {
/** Цвет плашки. Смысл (статус заявки и т.п.) назначает проект. */
variant?: BadgeVariant;
/** 'md' (по умолчанию) — обычный; 'sm' — компактный (для ячейки таблицы). */
size?: 'sm' | 'md';
children: React.ReactNode;
}
const variantClass: Record<BadgeVariant, string> = {
neutral: styles.neutral,
muted: styles.muted,
info: styles.info,
success: styles.success,
warning: styles.warning,
danger: styles.danger,
primary: styles.primary
};
/** Цветная плашка-бейдж. Цвет — через variant; что он означает, решает проект. */
export const Badge: React.FC<IBadgeProps> = ({ variant = 'neutral', size = 'md', children }) => {
const classes = [styles.badge, size === 'sm' ? styles.sm : '', variantClass[variant]]
.filter(Boolean)
.join(' ');
return <span className={classes}>{children}</span>;
};
+2
View File
@@ -10,6 +10,8 @@ export { PrintButton } from './PrintButton/PrintButton';
// --- Сообщения / плашки --- // --- Сообщения / плашки ---
export { Alert } from './Alert/Alert'; export { Alert } from './Alert/Alert';
export { RequestNumber } from './RequestNumber/RequestNumber'; export { RequestNumber } from './RequestNumber/RequestNumber';
export { Badge } from './Badge/Badge';
export type { IBadgeProps, BadgeVariant } from './Badge/Badge';
// --- Оболочка и раскладка формы --- // --- Оболочка и раскладка формы ---
export { FormCard } from './FormCard/FormCard'; export { FormCard } from './FormCard/FormCard';