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.
- package/dist/index.js +548 -33
- package/dist/vite/concat-css.js +13 -1
- package/dist/vite/postbuild.js +13 -1
- package/package.json +4 -3
- package/templates/elcrm-cursor/AGENTS.md +3 -1
- package/templates/elcrm-cursor/rules/elcrm-jsdoc.mdc +89 -0
- package/templates/elcrm-cursor/rules/elcrm-lib.mdc +1 -0
- package/templates/elcrm-cursor/rules/elcrm-packages.mdc +2 -2
- package/templates/elcrm-cursor/rules/elcrm-theme.mdc +1 -0
- package/templates/elcrm-cursor/rules/elcrm-tokens.mdc +40 -0
- package/templates/elcrm-cursor/rules/elcrm-ui.mdc +1 -0
- package/templates/elcrm-cursor/rules/elcrm.mdc +1 -1
- package/templates/elcrm-docs/CLI.elCRM.md +4 -3
- package/templates/elcrm-docs/COMPONENTS.elCRM.md +51 -46
- package/templates/panel/web/src/App.tsx +15 -1
- package/templates/panel/web/src/component/Header.tsx +19 -6
- package/templates/panel/web/src/lazyRoute.ts +6 -0
- package/templates/panel/web/src/lib/routeKey.ts +8 -1
- package/templates/panel/web/src/lib/theme.ts +20 -3
- package/templates/panel/web/src/modules/Account/index.tsx +12 -8
- package/templates/panel/web/src/modules/Account/router.sections.ts +5 -3
- package/templates/panel/web/src/modules/Account/sections/Profile.tsx +9 -4
- package/templates/panel/web/src/modules/Account/sections/Sessions.tsx +1 -1
- package/templates/panel/web/src/modules/Home/index.tsx +11 -4
- package/templates/panel/web/src/modules/Home/modal/Demo.tsx +10 -0
- package/templates/panel/web/src/modules/List/index.tsx +12 -11
- package/templates/panel/web/src/modules/List/router.sections.ts +6 -4
- package/templates/panel/web/src/modules/List/sections/Basic.tsx +3 -3
- package/templates/panel/web/src/modules/List/sections/Horizontal.tsx +1 -1
- package/templates/panel/web/src/modules/List/sections/Rows.tsx +6 -3
- package/templates/panel/web/src/modules/Settings/index.tsx +14 -8
- package/templates/panel/web/src/modules/Settings/router.sections.ts +7 -4
- package/templates/panel/web/src/modules/Settings/sections/Appearance.tsx +8 -4
- package/templates/panel/web/src/modules/Settings/sections/General.tsx +5 -1
- package/templates/panel/web/src/modules/Settings/sections/Profile.tsx +5 -1
- package/templates/panel/web/src/pages/Auth.tsx +10 -0
- package/templates/panel/web/src/pages/Main.tsx +7 -1
- package/templates/panel/web/src/state.ts +9 -0
- package/templates/panel/web/src/style/theme-dark.css +18 -87
- package/templates/panel/web/src/style/theme-light.css +18 -87
- package/templates/panel/web/src/style/theme.css +29 -78
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Card,
|
|
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
|
-
/**
|
|
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
|
-
<
|
|
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
|
-
</
|
|
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
|
-
|
|
13
|
-
|
|
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.
|
|
16
|
+
const LIST_KEYS = LIST_TABS.map((t) => t.value);
|
|
18
17
|
|
|
19
18
|
/**
|
|
20
|
-
* Демо `List` / `Item`
|
|
21
|
-
*
|
|
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
|
|
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>--
|
|
35
|
-
<code>theme-
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Вкладки List. `value` = `sections/{Value}.tsx`.
|
|
5
|
+
*/
|
|
4
6
|
export const LIST_TABS: TabSectionsItem[] = [
|
|
5
|
-
{
|
|
6
|
-
{
|
|
7
|
-
{
|
|
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>--
|
|
20
|
-
<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
|
-
/**
|
|
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>--
|
|
42
|
-
<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
|
-
|
|
10
|
-
|
|
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.
|
|
14
|
+
g.items.map((i) => i.value),
|
|
16
15
|
);
|
|
17
16
|
|
|
18
|
-
/**
|
|
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
|
|
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
|
-
|
|
31
|
-
|
|
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
|
-
/**
|
|
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
|
-
{
|
|
9
|
-
{
|
|
11
|
+
{ value: "Profile", label: "Профиль" },
|
|
12
|
+
{ value: "Appearance", label: "Оформление" },
|
|
10
13
|
],
|
|
11
14
|
},
|
|
12
15
|
{
|
|
13
16
|
label: "Система",
|
|
14
|
-
items: [{
|
|
17
|
+
items: [{ value: "General", label: "Общие" }],
|
|
15
18
|
},
|
|
16
19
|
];
|
|
17
20
|
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import {
|
|
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
|
-
<
|
|
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
|
-
</
|
|
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
|
-
--
|
|
153
|
-
|
|
154
|
-
--
|
|
155
|
-
--
|
|
156
|
-
--
|
|
157
|
-
|
|
158
|
-
--
|
|
159
|
-
--
|
|
160
|
-
--
|
|
161
|
-
|
|
162
|
-
--
|
|
163
|
-
--
|
|
164
|
-
|
|
165
|
-
--
|
|
166
|
-
--
|
|
167
|
-
--
|
|
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
|
-
--
|
|
153
|
-
|
|
154
|
-
--
|
|
155
|
-
--
|
|
156
|
-
--
|
|
157
|
-
|
|
158
|
-
--
|
|
159
|
-
--
|
|
160
|
-
--
|
|
161
|
-
|
|
162
|
-
--
|
|
163
|
-
--
|
|
164
|
-
|
|
165
|
-
--
|
|
166
|
-
--
|
|
167
|
-
--
|
|
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
|
}
|