feat:generic Badge(0.3.0)
This commit is contained in:
+17
@@ -118,6 +118,23 @@ Tabs (из CategoryTabs), Breadcrumbs (новый), Sidebar (из SideNav), AppL
|
||||
Drawer(?). Сначала «расцепить» от роутинга портала → сделать controlled
|
||||
(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/
|
||||
StatusBadge — оказались связаны с diagnostics/statuses, отложены) + ConfirmDialog/
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tnsu/ui-kit",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"description": "TNSU shared UI components for SPFx web parts",
|
||||
"author": "Timur Gorodetskiy",
|
||||
"license": "ISC",
|
||||
|
||||
@@ -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; }
|
||||
@@ -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>
|
||||
)
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
@@ -10,6 +10,8 @@ export { PrintButton } from './PrintButton/PrintButton';
|
||||
// --- Сообщения / плашки ---
|
||||
export { Alert } from './Alert/Alert';
|
||||
export { RequestNumber } from './RequestNumber/RequestNumber';
|
||||
export { Badge } from './Badge/Badge';
|
||||
export type { IBadgeProps, BadgeVariant } from './Badge/Badge';
|
||||
|
||||
// --- Оболочка и раскладка формы ---
|
||||
export { FormCard } from './FormCard/FormCard';
|
||||
|
||||
Reference in New Issue
Block a user