feat: Sidebar — разделители и перенос длинных названий (0.14.0)

Проп dividers рисует тонкие линии между пунктами (подпункты раскрытой
группы — без линий). Длинное название пункта переносится на вторую
строку вместо обрезки многоточием (не больше 2 строк).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Тимур Городецкий
2026-10-23 17:54:45 +05:00
parent 06e9007e73
commit 048fec0696
5 changed files with 46 additions and 6 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "@tnsu/ui-kit", "name": "@tnsu/ui-kit",
"version": "0.13.0", "version": "0.14.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@tnsu/ui-kit", "name": "@tnsu/ui-kit",
"version": "0.13.0", "version": "0.14.0",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@chromatic-com/storybook": "latest", "@chromatic-com/storybook": "latest",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@tnsu/ui-kit", "name": "@tnsu/ui-kit",
"version": "0.13.0", "version": "0.14.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",
+19 -3
View File
@@ -99,7 +99,8 @@
text-align: left; text-align: left;
// Пункт-ссылка (<a>) выглядит так же, как пункт-кнопка. // Пункт-ссылка (<a>) выглядит так же, как пункт-кнопка.
text-decoration: none; text-decoration: none;
white-space: nowrap; // Длинное название переносится (не больше 2 строк — см. .itemTitle), а не обрезается многоточием.
white-space: normal;
cursor: pointer; cursor: pointer;
transition: color .18s, background .18s, border-color .18s; transition: color .18s, background .18s, border-color .18s;
@@ -130,11 +131,26 @@
color: inherit; color: inherit;
} }
// Не больше 2 строк: совсем длинное название обрезается многоточием на второй строке.
.itemTitle { .itemTitle {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; line-height: 1.3;
overflow-wrap: anywhere;
}
// ---- Линии между пунктами (проп dividers) ----
// Линия — над каждым пунктом, кроме первого; подпункты раскрытой группы лежат внутри .group — их не трогаем.
.navDividers .items {
gap: 0;
> * + * {
border-top: 1px solid rgba(255, 255, 255, .06);
}
} }
.badge { .badge {
@@ -189,7 +205,7 @@ $sub-item-indent: 48px; // 18px отступ пункта + 3px маркер +
font-size: 13px; font-size: 13px;
text-align: left; text-align: left;
text-decoration: none; text-decoration: none;
white-space: nowrap; white-space: normal;
cursor: pointer; cursor: pointer;
transition: color .18s, background .18s; transition: color .18s, background .18s;
+20
View File
@@ -66,6 +66,7 @@ export const Collapsed: Story = {
// Пункт с children — раскрывающаяся группа; подпункт с href открывается в новой вкладке. // Пункт с children — раскрывающаяся группа; подпункт с href открывается в новой вкладке.
const ITEMS_WITH_GROUP: ISidebarItem[] = [ const ITEMS_WITH_GROUP: ISidebarItem[] = [
...ITEMS.slice(0, 3), ...ITEMS.slice(0, 3),
{ id: 'long', title: 'Загрузить работы из сметы проекта', icon: 'download' },
{ {
id: 'catalogs', id: 'catalogs',
title: 'Справочники', title: 'Справочники',
@@ -96,6 +97,25 @@ export const WithGroupAndLinks: Story = {
}, },
}; };
// Линии между пунктами; длинное название переносится на вторую строку.
export const WithDividers: Story = {
render: () => {
const [active, setActive] = useState('approvals');
const [collapsed, setCollapsed] = useState(false);
return (
<Sidebar
items={ITEMS_WITH_GROUP}
activeId={active}
onChange={setActive}
brand="Портал заявок"
collapsed={collapsed}
onToggleCollapsed={() => setCollapsed((c) => !c)}
dividers
/>
);
},
};
// Мобильный drawer: сузь окно браузера (или переключи Viewport в панели Storybook) // Мобильный drawer: сузь окно браузера (или переключи Viewport в панели Storybook)
// ниже 768px — сайдбар спрячется, а «☰ Меню» его выдвинет поверх контента. // ниже 768px — сайдбар спрячется, а «☰ Меню» его выдвинет поверх контента.
export const MobileDrawer: Story = { export const MobileDrawer: Story = {
+4
View File
@@ -24,6 +24,8 @@ export interface ISidebarProps {
mobileOpen?: boolean; mobileOpen?: boolean;
/** Закрыть мобильный drawer (клик по затемнению или выбор пункта). */ /** Закрыть мобильный drawer (клик по затемнению или выбор пункта). */
onMobileClose?: () => void; onMobileClose?: () => void;
/** Тонкие линии между пунктами (подпункты раскрытой группы — без линий, они читаются как одно целое). */
dividers?: boolean;
} }
/** /**
@@ -43,11 +45,13 @@ export const Sidebar: React.FC<ISidebarProps> = ({
onToggleCollapsed, onToggleCollapsed,
mobileOpen = false, mobileOpen = false,
onMobileClose, onMobileClose,
dividers = false,
}) => { }) => {
const navClasses = [ const navClasses = [
styles.nav, styles.nav,
collapsed ? styles.navCollapsed : '', collapsed ? styles.navCollapsed : '',
mobileOpen ? styles.navMobileOpen : '', mobileOpen ? styles.navMobileOpen : '',
dividers ? styles.navDividers : '',
] ]
.filter(Boolean) .filter(Boolean)
.join(' '); .join(' ');