elcrm 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/index.js +548 -33
  2. package/dist/vite/concat-css.js +13 -1
  3. package/dist/vite/postbuild.js +13 -1
  4. package/package.json +4 -3
  5. package/templates/elcrm-cursor/AGENTS.md +3 -1
  6. package/templates/elcrm-cursor/rules/elcrm-jsdoc.mdc +89 -0
  7. package/templates/elcrm-cursor/rules/elcrm-lib.mdc +1 -0
  8. package/templates/elcrm-cursor/rules/elcrm-packages.mdc +2 -2
  9. package/templates/elcrm-cursor/rules/elcrm-theme.mdc +1 -0
  10. package/templates/elcrm-cursor/rules/elcrm-tokens.mdc +40 -0
  11. package/templates/elcrm-cursor/rules/elcrm-ui.mdc +1 -0
  12. package/templates/elcrm-cursor/rules/elcrm.mdc +1 -1
  13. package/templates/elcrm-docs/CLI.elCRM.md +4 -3
  14. package/templates/elcrm-docs/COMPONENTS.elCRM.md +51 -46
  15. package/templates/panel/web/src/App.tsx +15 -1
  16. package/templates/panel/web/src/component/Header.tsx +19 -6
  17. package/templates/panel/web/src/lazyRoute.ts +6 -0
  18. package/templates/panel/web/src/lib/routeKey.ts +8 -1
  19. package/templates/panel/web/src/lib/theme.ts +20 -3
  20. package/templates/panel/web/src/modules/Account/index.tsx +12 -8
  21. package/templates/panel/web/src/modules/Account/router.sections.ts +5 -3
  22. package/templates/panel/web/src/modules/Account/sections/Profile.tsx +9 -4
  23. package/templates/panel/web/src/modules/Account/sections/Sessions.tsx +1 -1
  24. package/templates/panel/web/src/modules/Home/index.tsx +11 -4
  25. package/templates/panel/web/src/modules/Home/modal/Demo.tsx +10 -0
  26. package/templates/panel/web/src/modules/List/index.tsx +12 -11
  27. package/templates/panel/web/src/modules/List/router.sections.ts +6 -4
  28. package/templates/panel/web/src/modules/List/sections/Basic.tsx +3 -3
  29. package/templates/panel/web/src/modules/List/sections/Horizontal.tsx +1 -1
  30. package/templates/panel/web/src/modules/List/sections/Rows.tsx +6 -3
  31. package/templates/panel/web/src/modules/Settings/index.tsx +14 -8
  32. package/templates/panel/web/src/modules/Settings/router.sections.ts +7 -4
  33. package/templates/panel/web/src/modules/Settings/sections/Appearance.tsx +8 -4
  34. package/templates/panel/web/src/modules/Settings/sections/General.tsx +5 -1
  35. package/templates/panel/web/src/modules/Settings/sections/Profile.tsx +5 -1
  36. package/templates/panel/web/src/pages/Auth.tsx +10 -0
  37. package/templates/panel/web/src/pages/Main.tsx +7 -1
  38. package/templates/panel/web/src/state.ts +9 -0
  39. package/templates/panel/web/src/style/theme-dark.css +18 -87
  40. package/templates/panel/web/src/style/theme-light.css +18 -87
  41. package/templates/panel/web/src/style/theme.css +29 -78
@@ -1,6 +1,6 @@
1
1
  import { Card, EmptyState } from "@elcrm/components";
2
2
 
3
- /** Вкладка: демо списка (как вкладки в Children) */
3
+ /** Вкладка «Сессии»: демо `EmptyState` (контент из `sections/Sessions.tsx`). */
4
4
  export default function Sessions() {
5
5
  return (
6
6
  <Card>
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Card, Row, Section } from "@elcrm/components";
2
+ import { Card, Stack, Section } from "@elcrm/components";
3
3
  import { Button } from "@elcrm/button";
4
4
  import { Notice } from "@elcrm/notice";
5
5
  import { Modal } from "@elcrm/modal";
@@ -7,7 +7,14 @@ import { Notifications } from "@elcrm/notifications";
7
7
  import { Tooltip } from "@elcrm/tooltip";
8
8
  import useStateData from "../../state";
9
9
 
10
- /** Модуль «Главная» — демо стека @elcrm/* */
10
+ /**
11
+ * Модуль «Главная»: `Section` + `Card` + демо Modal / Notice.
12
+ *
13
+ * Роутер: `module=Home`. Модалка: `Modal.Open("Home", "Demo", { login })`.
14
+ *
15
+ * @example
16
+ * // LoadRoute variant="module"
17
+ */
11
18
  export default function Home() {
12
19
  const { user } = useStateData(["user"]);
13
20
 
@@ -40,7 +47,7 @@ export default function Home() {
40
47
  }
41
48
  >
42
49
  <Card title="Демо действий">
43
- <Row gap="0.75rem">
50
+ <Stack direction="row" gap="0.75rem">
44
51
  <Tooltip content="Открыть модалку">
45
52
  <Button label="Modal" onClick={openDemoModal} />
46
53
  </Tooltip>
@@ -49,7 +56,7 @@ export default function Home() {
49
56
  variant="secondary"
50
57
  onClick={pushNotice}
51
58
  />
52
- </Row>
59
+ </Stack>
53
60
  </Card>
54
61
  </Section>
55
62
  );
@@ -3,9 +3,19 @@ import { Button } from "@elcrm/button";
3
3
  import { Modal } from "@elcrm/modal";
4
4
 
5
5
  type Props = {
6
+ /** Логин текущего пользователя (из Home) */
6
7
  login?: string;
7
8
  };
8
9
 
10
+ /**
11
+ * Демо-окно модуля Home (`@elcrm/modal`).
12
+ *
13
+ * @param props.login - текст в теле
14
+ * @returns `Modal.Create` → `{ Open, Icon }` (файл: `modules/Home/modal/Demo.tsx`)
15
+ *
16
+ * @example
17
+ * Modal.Open("Home", "Demo", { login: "admin" })
18
+ */
9
19
  function Screen({ login }: Props) {
10
20
  return (
11
21
  <Modal.Main title="Демо Modal" size="s">
@@ -9,20 +9,21 @@ import { pickRouteKey } from "../../lib/routeKey";
9
9
  import { LIST_TAB_DEFAULT, LIST_TABS } from "./router.sections";
10
10
  import "./style.css";
11
11
 
12
- /** Lazy: modules/List/sections/{Key}.tsx */
13
- const resolveSection = createLazyResolver((key) =>
14
- import(`./sections/${key}.tsx`),
12
+ const resolveSection = createLazyResolver((value) =>
13
+ import(`./sections/${value}.tsx`),
15
14
  );
16
15
 
17
- const LIST_KEYS = LIST_TABS.map((t) => t.key);
16
+ const LIST_KEYS = LIST_TABS.map((t) => t.value);
18
17
 
19
18
  /**
20
- * Демо `List` / `Item` из @elcrm/components.
21
- * Стили: --list-*, --item-* в theme-*.css
19
+ * Демо `List` / `Item` (`@elcrm/components`).
20
+ *
21
+ * Роутер: ключ `listTab` (`Basic` | `Rows` | `Horizontal`).
22
+ * Токены строк: `--shell-*` в theme-light/dark.
22
23
  */
23
24
  export default function ListModule() {
24
25
  const tab = Router.useRouter("listTab");
25
- const activeKey = pickRouteKey(tab, LIST_KEYS, LIST_TAB_DEFAULT);
26
+ const value = pickRouteKey(tab, LIST_KEYS, LIST_TAB_DEFAULT);
26
27
 
27
28
  return (
28
29
  <Section
@@ -31,15 +32,15 @@ export default function ListModule() {
31
32
  description={
32
33
  <>
33
34
  Пример настройки <code>List</code> и <code>Item</code>. Токены{" "}
34
- <code>--list-*</code>, <code>--item-*</code> в{" "}
35
- <code>theme-dark.css</code> / <code>theme-light.css</code>.
35
+ <code>--shell-*</code> в <code>theme-dark.css</code> /{" "}
36
+ <code>theme-light.css</code>.
36
37
  </>
37
38
  }
38
39
  >
39
40
  <TabSections
40
41
  items={LIST_TABS}
41
- activeKey={activeKey}
42
- onChange={(key) => Router.setRouter("listTab", key)}
42
+ value={value}
43
+ onValueChange={(next) => Router.setRouter("listTab", next)}
43
44
  resolveSection={resolveSection}
44
45
  loading={<Loading />}
45
46
  navLabel="Примеры списка"
@@ -1,10 +1,12 @@
1
1
  import type { TabSectionsItem } from "@elcrm/components";
2
2
 
3
- /** Вкладки демо List / Item */
3
+ /**
4
+ * Вкладки List. `value` = `sections/{Value}.tsx`.
5
+ */
4
6
  export const LIST_TABS: TabSectionsItem[] = [
5
- { key: "Basic", label: "Базовый" },
6
- { key: "Rows", label: "Строки", badge: 3 },
7
- { key: "Horizontal", label: "Ряд" },
7
+ { value: "Basic", label: "Базовый" },
8
+ { value: "Rows", label: "Строки", badge: 3 },
9
+ { value: "Horizontal", label: "Ряд" },
8
10
  ];
9
11
 
10
12
  export const LIST_TAB_DEFAULT = "Basic";
@@ -8,7 +8,7 @@ const ITEMS = [
8
8
  { key: "settings", label: "Настройки", hint: "NavSections" },
9
9
  ];
10
10
 
11
- /** Кликабельные Item (button) + active */
11
+ /** Кликабельные `Item` (`as` button) + `active`. Токены hover/selected — `--shell-*`. */
12
12
  export default function Basic() {
13
13
  const [active, setActive] = useState("home");
14
14
 
@@ -16,8 +16,8 @@ export default function Basic() {
16
16
  <Card title="List + Item (button)">
17
17
  <p className="muted list-demo-hint">
18
18
  Клик выбирает строку (`active`). Hover / active — через{" "}
19
- <code>--item-background-hover</code>,{" "}
20
- <code>--item-background-active</code>.
19
+ <code>--shell-background-hover</code>,{" "}
20
+ <code>--shell-background-selected</code>.
21
21
  </p>
22
22
  <List>
23
23
  {ITEMS.map((item) => (
@@ -2,7 +2,7 @@ import { Card, Item, List } from "@elcrm/components";
2
2
 
3
3
  const CHIPS = ["Все", "Новые", "Активные", "Архив"];
4
4
 
5
- /** List row — горизонтальный ряд Item */
5
+ /** Горизонтальный ряд: проп `row` у `List`, чипы как `Item`. */
6
6
  export default function Horizontal() {
7
7
  return (
8
8
  <Card title="List row">
@@ -32,14 +32,17 @@ const ROWS: Row[] = [
32
32
  },
33
33
  ];
34
34
 
35
- /** Плотные строки как в списке «Дети» */
35
+ /**
36
+ * Плотные строки списка: `Item as="li"` + `Avatar` + `Badge`.
37
+ * Оболочка — `--shell-padding` / `--shell-radius` / `--shell-gap-sm`.
38
+ */
36
39
  export default function Rows() {
37
40
  return (
38
41
  <Card title="Строки (layout внутри Item)">
39
42
  <p className="muted list-demo-hint">
40
43
  Разметка контента — ваша; оболочка и отступы — токены{" "}
41
- <code>--item-padding</code>, <code>--item-radius</code>,{" "}
42
- <code>--list-gap</code>.
44
+ <code>--shell-padding</code>, <code>--shell-radius</code>,{" "}
45
+ <code>--shell-gap-sm</code>.
43
46
  </p>
44
47
  <List className="list-demo-rows">
45
48
  {ROWS.map((row) => (
@@ -6,19 +6,25 @@ import {
6
6
  SETTINGS_SECTION_GROUPS,
7
7
  } from "./router.sections";
8
8
 
9
- /** Lazy: modules/Settings/sections/{Key}.tsx */
10
- const resolveSection = createLazyResolver((key) =>
11
- import(`./sections/${key}.tsx`),
9
+ const resolveSection = createLazyResolver((value) =>
10
+ import(`./sections/${value}.tsx`),
12
11
  );
13
12
 
14
13
  const SETTINGS_KEYS = SETTINGS_SECTION_GROUPS.flatMap((g) =>
15
- g.items.map((i) => i.key),
14
+ g.items.map((i) => i.value),
16
15
  );
17
16
 
18
- /** Модуль «Настройки»: сайдбар + секции из ./sections */
17
+ /**
18
+ * Настройки: `NavSections` (сайдбар + lazy-секции).
19
+ *
20
+ * Роутер: ключ `section` (`Profile` | `Appearance` | `General`).
21
+ * Файлы: `sections/{Value}.tsx`, `export default`.
22
+ *
23
+ * @see SETTINGS_SECTION_GROUPS
24
+ */
19
25
  export default function Settings() {
20
26
  const section = Router.useRouter("section");
21
- const activeKey = pickRouteKey(
27
+ const value = pickRouteKey(
22
28
  section,
23
29
  SETTINGS_KEYS,
24
30
  SETTINGS_SECTION_DEFAULT,
@@ -27,8 +33,8 @@ export default function Settings() {
27
33
  return (
28
34
  <NavSections
29
35
  groups={SETTINGS_SECTION_GROUPS}
30
- activeKey={activeKey}
31
- onChange={(key) => Router.setRouter("section", key)}
36
+ value={value}
37
+ onValueChange={(next) => Router.setRouter("section", next)}
32
38
  resolveSection={resolveSection}
33
39
  loading={<Loading />}
34
40
  navLabel="Разделы настроек"
@@ -1,17 +1,20 @@
1
1
  import type { NavSectionsGroup } from "@elcrm/components";
2
2
 
3
- /** Секции модуля Settings (ключ = файл sections/{Key}.tsx) */
3
+ /**
4
+ * Группы сайдбара Settings.
5
+ * `items[].value` = имя файла `sections/{Value}.tsx`.
6
+ */
4
7
  export const SETTINGS_SECTION_GROUPS: NavSectionsGroup[] = [
5
8
  {
6
9
  label: "Личное",
7
10
  items: [
8
- { key: "Profile", label: "Профиль" },
9
- { key: "Appearance", label: "Оформление" },
11
+ { value: "Profile", label: "Профиль" },
12
+ { value: "Appearance", label: "Оформление" },
10
13
  ],
11
14
  },
12
15
  {
13
16
  label: "Система",
14
- items: [{ key: "General", label: "Общие" }],
17
+ items: [{ value: "General", label: "Общие" }],
15
18
  },
16
19
  ];
17
20
 
@@ -1,9 +1,13 @@
1
- import { Row, Section } from "@elcrm/components";
1
+ import { Stack, Section } from "@elcrm/components";
2
2
  import { Button } from "@elcrm/button";
3
3
  import { getTheme, setTheme, type ThemeMode } from "../../../lib/theme";
4
4
  import { useState } from "react";
5
5
 
6
- /** Секция настроек: тема оформления */
6
+ /**
7
+ * Секция настроек: тема (`light` | `dark`).
8
+ *
9
+ * Кнопки `@elcrm/button`; значение — `lib/theme` (localStorage + `data-theme`).
10
+ */
7
11
  export default function Appearance() {
8
12
  const [theme, setThemeState] = useState<ThemeMode>(() => getTheme());
9
13
 
@@ -19,7 +23,7 @@ export default function Appearance() {
19
23
  description="Тема интерфейса панели. Значение сохраняется в localStorage."
20
24
  >
21
25
  <Section variant="block" title="Тема">
22
- <Row gap={8}>
26
+ <Stack direction="row" gap={8}>
23
27
  <Button
24
28
  label="Светлая"
25
29
  width="s"
@@ -32,7 +36,7 @@ export default function Appearance() {
32
36
  variant={theme === "dark" ? "primary" : "secondary"}
33
37
  onClick={() => apply("dark")}
34
38
  />
35
- </Row>
39
+ </Stack>
36
40
  </Section>
37
41
  </Section>
38
42
  );
@@ -3,7 +3,11 @@ import { Button } from "@elcrm/button";
3
3
  import { Notice } from "@elcrm/notice";
4
4
  import { StringField, useForm } from "@elcrm/form";
5
5
 
6
- /** Секция настроек: общие (демо) */
6
+ /**
7
+ * Секция настроек: общие (демо, без API).
8
+ *
9
+ * `StringField` name / description + `Button` → `Notice.Success`.
10
+ */
7
11
  export default function General() {
8
12
  const form = useForm({
9
13
  name: "Panel",
@@ -6,7 +6,11 @@ import { Notice } from "@elcrm/notice";
6
6
  import { DisplayField, EmailField, StringField, useForm } from "@elcrm/form";
7
7
  import useStateData from "../../../state";
8
8
 
9
- /** Секция настроек: профиль */
9
+ /**
10
+ * Секция настроек: профиль (`Section` + `variant="block"`).
11
+ *
12
+ * Те же поля, что вкладка Account/Profile: `auth/profile`.
13
+ */
10
14
  export default function Profile() {
11
15
  const { user, loadUser } = useStateData(["user", "loadUser"]);
12
16
  const form = useForm({
@@ -8,6 +8,16 @@ import { PasswordField, StringField, useForm } from "@elcrm/form";
8
8
  import { Crypto } from "@elcrm/crypto";
9
9
  import { usePasskeySupport } from "@elcrm/passkey";
10
10
 
11
+ /**
12
+ * Экран входа (`Section variant="auth"`).
13
+ *
14
+ * Поля `@elcrm/form`: `login` (`StringField`), `password` (`PasswordField`) + `useForm`.
15
+ * Submit: `Button onSend` → `Api.query("auth/pass", { login, password })`.
16
+ * Успех: `Router.mergeRouter({ page: "Main", module: "Home" })`.
17
+ *
18
+ * @example
19
+ * // LoadRoute variant="page" → Auth.tsx
20
+ */
11
21
  export default function Auth() {
12
22
  const form = useForm({ login: "", password: "" });
13
23
  const passkeySupport = usePasskeySupport();
@@ -4,11 +4,17 @@ import useStateData from "../state";
4
4
  import { LoadRoute } from "@elcrm/router";
5
5
  import { createLazyResolver } from "../lazyRoute";
6
6
 
7
- /** Модули: src/modules/{Home|List|Account|Settings}/index.tsx */
8
7
  const resolveModule = createLazyResolver((segment) =>
9
8
  import(`../modules/${segment}/index.tsx`),
10
9
  );
11
10
 
11
+ /**
12
+ * Оболочка авторизованной зоны: `Layout` + `Header` + модули.
13
+ *
14
+ * `LoadRoute` variant=`module`, default `Home`.
15
+ * Чанки: `src/modules/{Home|List|Account|Settings}/index.tsx`.
16
+ * `preUpload` — `loadUser()` (`auth/me`).
17
+ */
12
18
  export default function Main() {
13
19
  const root = document.getElementById("root");
14
20
  if (root) root.dataset.page = "main";
@@ -1,6 +1,7 @@
1
1
  import { State } from "@elcrm/state";
2
2
  import { Api } from "@elcrm/api";
3
3
 
4
+ /** Пользователь панели (поля с `auth/me` / `auth/profile`). */
4
5
  export type PanelUser = {
5
6
  id: number;
6
7
  login: string;
@@ -12,9 +13,17 @@ export type PanelUser = {
12
13
 
13
14
  type Store = {
14
15
  user: PanelUser | null;
16
+ /** Подтянуть профиль: `Api.query("auth/me")`. */
15
17
  loadUser: () => Promise<void>;
16
18
  };
17
19
 
20
+ /**
21
+ * Глобальный store `@elcrm/state`: текущий user.
22
+ *
23
+ * @example
24
+ * const { user } = useStateData(["user"]);
25
+ * await useStateData.getState().loadUser();
26
+ */
18
27
  const useStateData = State.create<Store>((set) => ({
19
28
  user: null,
20
29
  loadUser: async () => {
@@ -16,6 +16,7 @@ body[data-theme="dark"] {
16
16
  --accent: #5b8cff;
17
17
  --danger: #ff6b6b;
18
18
  --success: #3dd68c;
19
+ --warning: #f59e0b;
19
20
  --shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
20
21
 
21
22
  /* —— button —— */
@@ -148,93 +149,23 @@ body[data-theme="dark"] {
148
149
  --color-text: var(--text);
149
150
  --color-field-focus: var(--field-background);
150
151
 
151
- /* —— @elcrm/components —— */
152
- --layout-background: var(--bg);
153
-
154
- --header-background: color-mix(in srgb, var(--panel) 92%, var(--bg));
155
- --header-color: var(--text);
156
- --header-border: var(--line);
157
-
158
- --footer-background: transparent;
159
- --footer-color: var(--muted);
160
- --footer-border: var(--line);
161
-
162
- --item-background: transparent;
163
- --item-background-hover: color-mix(in srgb, var(--text) 8%, transparent);
164
- --item-background-active: color-mix(in srgb, var(--text) 12%, transparent);
165
- --item-color: var(--text);
166
- --item-color-muted: var(--muted);
167
- --item-border: transparent;
168
-
169
- --card-background: var(--panel);
170
- --card-border: var(--line);
171
- --card-shadow: var(--shadow);
172
-
173
- --menu-item-background: transparent;
174
- --menu-item-background-hover: color-mix(in srgb, var(--text) 8%, transparent);
175
- --menu-item-background-active: color-mix(
176
- in srgb,
177
- var(--text) 10%,
178
- transparent
179
- );
180
- --menu-item-color: var(--muted);
181
- --menu-item-color-active: var(--text);
182
-
183
- --loading-color: var(--muted);
184
-
185
- --section-title-color: var(--text);
186
- --section-description-color: var(--muted);
187
- --section-auth-card-background: var(--panel);
188
- --section-auth-card-border: var(--line);
189
- --section-auth-card-shadow: var(--shadow);
190
- --section-block-border: var(--line);
191
-
192
- --nav-sections-label-color: var(--muted);
193
- --nav-sections-item-color: var(--text);
194
- --nav-sections-item-background-hover: color-mix(
195
- in srgb,
196
- var(--text) 8%,
197
- transparent
198
- );
199
- --nav-sections-item-background-active: color-mix(
200
- in srgb,
201
- var(--text) 10%,
202
- transparent
203
- );
204
- --nav-sections-accent: var(--accent);
205
- --nav-sections-icon-color: var(--muted);
206
- --nav-sections-group-border: var(--line);
207
- --nav-sections-footer-border: var(--line);
208
-
209
- --tab-sections-border: var(--line);
210
- --tab-sections-color: var(--muted);
211
- --tab-sections-color-active: var(--text);
212
- --tab-sections-accent: var(--text);
213
- --tab-sections-badge-background: var(--danger);
214
- --tab-sections-badge-color: #ffffff;
215
-
216
- --avatar-background: var(--accent);
217
- --avatar-color: var(--button-primary-fg, #fff);
218
- --avatar-border: 1px solid var(--line);
152
+ /* —— @elcrm/components: shell (общие) + узкие avatar —— */
153
+ --shell-color: var(--text);
154
+ --shell-color-muted: var(--muted);
155
+ --shell-color-accent: var(--accent);
156
+ --shell-color-danger: var(--danger);
157
+ --shell-color-success: var(--success);
158
+ --shell-color-warning: var(--warning);
159
+ --shell-border: var(--line);
160
+ --shell-background: var(--panel);
161
+ --shell-background-muted: var(--bg);
162
+ --shell-background-hover: color-mix(in srgb, var(--text) 8%, transparent);
163
+ --shell-background-selected: color-mix(in srgb, var(--accent) 14%, transparent);
164
+ --shell-shadow: var(--shadow);
165
+
166
+ --avatar-background: var(--shell-color-accent);
167
+ --avatar-color: var(--button-primary-fg);
168
+ --avatar-border: 1px solid var(--shell-border);
219
169
  --avatar-outline-active: 2px solid
220
170
  color-mix(in srgb, var(--accent) 70%, white);
221
-
222
- --badge-neutral-background: color-mix(in srgb, var(--text) 10%, transparent);
223
- --badge-neutral-color: var(--text);
224
- --badge-accent-background: color-mix(in srgb, var(--accent) 22%, transparent);
225
- --badge-accent-color: var(--accent);
226
- --badge-success-background: color-mix(in srgb, var(--success, #22c55e) 22%, transparent);
227
- --badge-success-color: var(--success, #22c55e);
228
- --badge-warning-background: color-mix(in srgb, var(--warning, #f59e0b) 22%, transparent);
229
- --badge-warning-color: var(--warning, #f59e0b);
230
- --badge-danger-background: color-mix(in srgb, var(--danger) 22%, transparent);
231
- --badge-danger-color: var(--danger);
232
-
233
- --brand-color: var(--header-color);
234
- --brand-color-hover: var(--header-color);
235
-
236
- --empty-state-color: var(--muted);
237
- --empty-state-icon-color: var(--muted);
238
- --empty-state-title-color: var(--text);
239
- --empty-state-description-color: var(--muted);
240
171
  }
@@ -16,6 +16,7 @@ body[data-theme="light"] {
16
16
  --accent: #3b6ef5;
17
17
  --danger: #d64545;
18
18
  --success: #1f9d62;
19
+ --warning: #d97706;
19
20
  --shadow: 0 8px 24px rgba(26, 31, 41, 0.1);
20
21
 
21
22
  /* —— button —— */
@@ -148,93 +149,23 @@ body[data-theme="light"] {
148
149
  --color-text: var(--text);
149
150
  --color-field-focus: var(--field-background);
150
151
 
151
- /* —— @elcrm/components —— */
152
- --layout-background: var(--bg);
153
-
154
- --header-background: color-mix(in srgb, var(--panel) 96%, var(--bg));
155
- --header-color: var(--text);
156
- --header-border: var(--line);
157
-
158
- --footer-background: transparent;
159
- --footer-color: var(--muted);
160
- --footer-border: var(--line);
161
-
162
- --item-background: transparent;
163
- --item-background-hover: color-mix(in srgb, var(--text) 6%, transparent);
164
- --item-background-active: color-mix(in srgb, var(--text) 10%, transparent);
165
- --item-color: var(--text);
166
- --item-color-muted: var(--muted);
167
- --item-border: transparent;
168
-
169
- --card-background: var(--panel);
170
- --card-border: var(--line);
171
- --card-shadow: var(--shadow);
172
-
173
- --menu-item-background: transparent;
174
- --menu-item-background-hover: color-mix(in srgb, var(--text) 6%, transparent);
175
- --menu-item-background-active: color-mix(
176
- in srgb,
177
- var(--text) 10%,
178
- transparent
179
- );
180
- --menu-item-color: var(--muted);
181
- --menu-item-color-active: var(--text);
182
-
183
- --loading-color: var(--muted);
184
-
185
- --section-title-color: var(--text);
186
- --section-description-color: var(--muted);
187
- --section-auth-card-background: var(--panel);
188
- --section-auth-card-border: var(--line);
189
- --section-auth-card-shadow: var(--shadow);
190
- --section-block-border: var(--line);
191
-
192
- --nav-sections-label-color: var(--muted);
193
- --nav-sections-item-color: var(--text);
194
- --nav-sections-item-background-hover: color-mix(
195
- in srgb,
196
- var(--text) 6%,
197
- transparent
198
- );
199
- --nav-sections-item-background-active: color-mix(
200
- in srgb,
201
- var(--text) 10%,
202
- transparent
203
- );
204
- --nav-sections-accent: var(--accent);
205
- --nav-sections-icon-color: var(--muted);
206
- --nav-sections-group-border: var(--line);
207
- --nav-sections-footer-border: var(--line);
208
-
209
- --tab-sections-border: var(--line);
210
- --tab-sections-color: var(--muted);
211
- --tab-sections-color-active: var(--text);
212
- --tab-sections-accent: var(--text);
213
- --tab-sections-badge-background: var(--danger);
214
- --tab-sections-badge-color: #ffffff;
215
-
216
- --avatar-background: var(--accent);
217
- --avatar-color: var(--button-primary-fg, #fff);
218
- --avatar-border: 1px solid var(--line);
152
+ /* —— @elcrm/components: shell (общие) + узкие avatar —— */
153
+ --shell-color: var(--text);
154
+ --shell-color-muted: var(--muted);
155
+ --shell-color-accent: var(--accent);
156
+ --shell-color-danger: var(--danger);
157
+ --shell-color-success: var(--success);
158
+ --shell-color-warning: var(--warning);
159
+ --shell-border: var(--line);
160
+ --shell-background: var(--panel);
161
+ --shell-background-muted: var(--bg);
162
+ --shell-background-hover: color-mix(in srgb, var(--text) 6%, transparent);
163
+ --shell-background-selected: color-mix(in srgb, var(--accent) 10%, transparent);
164
+ --shell-shadow: var(--shadow);
165
+
166
+ --avatar-background: var(--shell-color-accent);
167
+ --avatar-color: var(--button-primary-fg);
168
+ --avatar-border: 1px solid var(--shell-border);
219
169
  --avatar-outline-active: 2px solid
220
170
  color-mix(in srgb, var(--accent) 70%, white);
221
-
222
- --badge-neutral-background: color-mix(in srgb, var(--text) 8%, transparent);
223
- --badge-neutral-color: var(--text);
224
- --badge-accent-background: color-mix(in srgb, var(--accent) 16%, transparent);
225
- --badge-accent-color: var(--accent);
226
- --badge-success-background: color-mix(in srgb, var(--success, #16a34a) 16%, transparent);
227
- --badge-success-color: var(--success, #16a34a);
228
- --badge-warning-background: color-mix(in srgb, var(--warning, #d97706) 16%, transparent);
229
- --badge-warning-color: var(--warning, #d97706);
230
- --badge-danger-background: color-mix(in srgb, var(--danger) 16%, transparent);
231
- --badge-danger-color: var(--danger);
232
-
233
- --brand-color: var(--header-color);
234
- --brand-color-hover: var(--header-color);
235
-
236
- --empty-state-color: var(--muted);
237
- --empty-state-icon-color: var(--muted);
238
- --empty-state-title-color: var(--text);
239
- --empty-state-description-color: var(--muted);
240
171
  }