- recharts: все hex/hsl палитры → var(--chart-1..5), семантика → var(--info/success/warning/destructive) - палитровые Tailwind-классы (red/blue/green/amber и т.д.) → семантические классы через color-mix (Tailwind v3 не генерирует alpha для var-цветов) - ui/table.tsx: шапка по гайду (bg-muted/50, text-[12px]), строки h-[var(--table-row-height,40px)], ячейки px-3, hover muted 40% - lib/field-styles.ts (порт из основного клиента) + fieldControlClass в column-filter - app-sidebar: брендинг «ОмегаПром / Финансы», компактные отступы - bottom-nav.tsx: мобильная нижняя панель (Обзор/Разделы/Настройки) по референсу FinanceBottomNav, safe-area-bottom в index.css - переключатель темы Sun/Moon в хедере (useDi2Theme), SidebarTrigger скрыт на мобильном - заголовки страниц text-lg font-semibold
290 lines
9.8 KiB
CSS
290 lines
9.8 KiB
CSS
/* Общий CSS встроенных скинов iistwin (generateAllSkinsCss → [data-skin][data-theme]).
|
|
Путь относительно этого файла (client-di2/src/index.css). */
|
|
@import '../../client/src/themes/styles/generated-skins.css';
|
|
|
|
/* Конфиг Tailwind субаппа DI2 — иначе postcss-плагин возьмёт корневой конфиг iistwin */
|
|
@config "../tailwind.config.ts";
|
|
|
|
@tailwind base;
|
|
@tailwind components;
|
|
@tailwind utilities;
|
|
|
|
/*
|
|
* Fallback переменные для случая, когда data-skin/data-theme ещё не применены
|
|
* (до монтирования Di2ThemeProvider). Основные значения берутся из generated-skins.css.
|
|
* Блоки скопированы из client/src/index.css — DI2 теперь на тех же токенах, что iistwin.
|
|
*/
|
|
:root {
|
|
--background: hsl(0 0% 100%);
|
|
--foreground: hsl(220 10% 15%);
|
|
--card: hsl(0 0% 100%);
|
|
--card-foreground: hsl(220 10% 15%);
|
|
--popover: hsl(0 0% 100%);
|
|
--popover-foreground: hsl(220 10% 15%);
|
|
--primary: hsl(220 10% 15%);
|
|
--primary-foreground: hsl(0 0% 100%);
|
|
--secondary: hsl(220 5% 96%);
|
|
--secondary-foreground: hsl(220 10% 15%);
|
|
--muted: hsl(220 5% 96%);
|
|
--muted-foreground: hsl(220 5% 45%);
|
|
--accent: hsl(220 5% 93%);
|
|
--accent-foreground: hsl(220 10% 15%);
|
|
--destructive: hsl(0 72% 51%);
|
|
--destructive-foreground: hsl(0 0% 100%);
|
|
--border: hsl(220 5% 90%);
|
|
--input: hsl(0 0% 100%);
|
|
--ring: hsl(220 10% 15%);
|
|
|
|
--status-done: hsl(142 50% 45%);
|
|
--status-progress: hsl(45 90% 50%);
|
|
--status-overdue: hsl(0 70% 55%);
|
|
--status-paused: hsl(220 5% 60%);
|
|
|
|
--warning: hsl(48 96% 89%);
|
|
--warning-foreground: hsl(25 83% 31%);
|
|
--success: hsl(141 84% 93%);
|
|
--success-foreground: hsl(142 72% 24%);
|
|
--info: hsl(214 95% 93%);
|
|
--info-foreground: hsl(224 71% 40%);
|
|
|
|
--chart-1: hsl(220 10% 25%);
|
|
--chart-2: hsl(142 50% 45%);
|
|
--chart-3: hsl(45 90% 50%);
|
|
--chart-4: hsl(200 70% 50%);
|
|
--chart-5: hsl(0 70% 55%);
|
|
|
|
--sidebar: hsl(0 0% 100%);
|
|
--sidebar-foreground: hsl(220 10% 15%);
|
|
--sidebar-primary: hsl(220 10% 15%);
|
|
--sidebar-primary-foreground: hsl(0 0% 100%);
|
|
--sidebar-accent: hsl(220 5% 96%);
|
|
--sidebar-accent-foreground: hsl(220 10% 15%);
|
|
--sidebar-border: hsl(220 5% 92%);
|
|
--sidebar-ring: hsl(220 10% 15%);
|
|
|
|
--font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
--font-mono: "DM Mono", "SF Mono", "Monaco", "Inconsolata", monospace;
|
|
|
|
--radius: 0.25rem;
|
|
|
|
--shadow-2xs: none;
|
|
--shadow-xs: none;
|
|
--shadow-sm: none;
|
|
--shadow: none;
|
|
--shadow-md: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
|
|
--shadow-lg: 0 1px 3px 0 rgba(0, 0, 0, 0.05);
|
|
--shadow-xl: 0 2px 4px 0 rgba(0, 0, 0, 0.05);
|
|
--shadow-2xl: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
|
|
|
|
--tracking-normal: -0.01em;
|
|
--spacing: 0.25rem;
|
|
|
|
--elevate-1: rgba(0, 0, 0, 0.05);
|
|
--elevate-2: rgba(0, 0, 0, 0.08);
|
|
|
|
/* DI2-only переменные: теперь производные от семантических токенов скинов.
|
|
Раньше считались relative-color из голых HSL-троек — больше не нужно. */
|
|
--card-border: var(--border);
|
|
--popover-border: var(--border);
|
|
--primary-border: color-mix(in oklab, var(--primary) 82%, black);
|
|
--secondary-border: color-mix(in oklab, var(--secondary) 82%, black);
|
|
--muted-border: color-mix(in oklab, var(--muted) 82%, black);
|
|
--accent-border: color-mix(in oklab, var(--accent) 82%, black);
|
|
--destructive-border: color-mix(in oklab, var(--destructive) 82%, black);
|
|
--sidebar-primary-border: color-mix(in oklab, var(--sidebar-primary) 82%, black);
|
|
--sidebar-accent-border: color-mix(in oklab, var(--sidebar-accent) 82%, black);
|
|
--button-outline: color-mix(in oklab, var(--primary) 35%, transparent);
|
|
--badge-outline: color-mix(in oklab, var(--muted-foreground) 35%, transparent);
|
|
}
|
|
|
|
.dark {
|
|
--elevate-1: rgba(255, 255, 255, 0.05);
|
|
--elevate-2: rgba(255, 255, 255, 0.08);
|
|
--background: hsl(220 10% 8%);
|
|
--foreground: hsl(220 5% 92%);
|
|
--card: hsl(220 10% 10%);
|
|
--card-foreground: hsl(220 5% 92%);
|
|
--popover: hsl(220 10% 10%);
|
|
--popover-foreground: hsl(220 5% 92%);
|
|
--primary: hsl(0 0% 100%);
|
|
--primary-foreground: hsl(220 10% 8%);
|
|
--secondary: hsl(220 10% 14%);
|
|
--secondary-foreground: hsl(220 5% 92%);
|
|
--muted: hsl(220 10% 14%);
|
|
--muted-foreground: hsl(220 5% 55%);
|
|
--accent: hsl(220 10% 16%);
|
|
--accent-foreground: hsl(220 5% 92%);
|
|
--destructive: hsl(0 70% 55%);
|
|
--destructive-foreground: hsl(0 0% 100%);
|
|
--border: hsl(220 10% 18%);
|
|
--input: hsl(220 10% 12%);
|
|
--ring: hsl(0 0% 100%);
|
|
|
|
--status-done: hsl(142 50% 55%);
|
|
--status-progress: hsl(45 90% 55%);
|
|
--status-overdue: hsl(0 70% 60%);
|
|
--status-paused: hsl(220 5% 55%);
|
|
|
|
--warning: hsl(32 92% 14%);
|
|
--warning-foreground: hsl(43 96% 56%);
|
|
--success: hsl(144 80% 10%);
|
|
--success-foreground: hsl(142 71% 58%);
|
|
--info: hsl(224 64% 21%);
|
|
--info-foreground: hsl(213 97% 81%);
|
|
|
|
--chart-1: hsl(220 5% 70%);
|
|
--chart-2: hsl(142 50% 55%);
|
|
--chart-3: hsl(45 90% 55%);
|
|
--chart-4: hsl(200 70% 55%);
|
|
--chart-5: hsl(0 70% 60%);
|
|
|
|
--sidebar: hsl(220 10% 8%);
|
|
--sidebar-foreground: hsl(220 5% 92%);
|
|
--sidebar-primary: hsl(0 0% 100%);
|
|
--sidebar-primary-foreground: hsl(220 10% 8%);
|
|
--sidebar-accent: hsl(220 10% 14%);
|
|
--sidebar-accent-foreground: hsl(220 5% 92%);
|
|
--sidebar-border: hsl(220 10% 16%);
|
|
--sidebar-ring: hsl(0 0% 100%);
|
|
|
|
--radius: 0.25rem;
|
|
|
|
--shadow-md: 0 1px 2px 0 rgba(0, 0, 0, 0.15);
|
|
--shadow-lg: 0 2px 4px 0 rgba(0, 0, 0, 0.2);
|
|
--shadow-xl: 0 4px 6px -1px rgba(0, 0, 0, 0.2);
|
|
--shadow-2xl: 0 8px 10px -2px rgba(0, 0, 0, 0.25);
|
|
}
|
|
|
|
@layer base {
|
|
* {
|
|
@apply border-border;
|
|
}
|
|
|
|
body {
|
|
@apply font-sans antialiased bg-background text-foreground;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Using the elevate system.
|
|
* Automatic contrast adjustment.
|
|
*
|
|
* <element className="hover-elevate" />
|
|
* <element className="active-elevate-2" />
|
|
*
|
|
* // Using the tailwind utility when a data attribute is "on"
|
|
* <element className="toggle-elevate data-[state=on]:toggle-elevated" />
|
|
* // Or manually controlling the toggle state
|
|
* <element className="toggle-elevate toggle-elevated" />
|
|
*
|
|
* Elevation systems have to handle many states.
|
|
* - not-hovered, vs. hovered vs. active (three mutually exclusive states)
|
|
* - toggled or not
|
|
* - focused or not (this is not handled with these utilities)
|
|
*
|
|
* Even without handling focused or not, this is six possible combinations that
|
|
* need to be distinguished from eachother visually.
|
|
*/
|
|
@layer utilities {
|
|
|
|
/* Hide ugly search cancel button in Chrome until we can style it properly */
|
|
input[type="search"]::-webkit-search-cancel-button {
|
|
@apply hidden;
|
|
}
|
|
|
|
/* Placeholder styling for contentEditable div */
|
|
[contenteditable][data-placeholder]:empty::before {
|
|
content: attr(data-placeholder);
|
|
color: var(--muted-foreground);
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* .no-default-hover-elevate/no-default-active-elevate is an escape hatch so consumers of
|
|
* buttons/badges can remove the automatic brightness adjustment on interactions
|
|
* and program their own. */
|
|
.no-default-hover-elevate {}
|
|
|
|
.no-default-active-elevate {}
|
|
|
|
|
|
/**
|
|
* Toggleable backgrounds go behind the content. Hoverable/active goes on top.
|
|
* This way they can stack/compound. Both will overlap the parent's borders!
|
|
* So borders will be automatically adjusted both on toggle, and hover/active,
|
|
* and they will be compounded.
|
|
*/
|
|
.toggle-elevate::before,
|
|
.toggle-elevate-2::before {
|
|
content: "";
|
|
pointer-events: none;
|
|
position: absolute;
|
|
inset: 0px;
|
|
/*border-radius: inherit; match rounded corners */
|
|
border-radius: inherit;
|
|
z-index: -1;
|
|
/* sits behind content but above backdrop */
|
|
}
|
|
|
|
.toggle-elevate.toggle-elevated::before {
|
|
background-color: var(--elevate-2);
|
|
}
|
|
|
|
/* If there's a 1px border, adjust the inset so that it covers that parent's border */
|
|
.border.toggle-elevate::before {
|
|
inset: -1px;
|
|
}
|
|
|
|
/* Does not work on elements with overflow:hidden! */
|
|
.hover-elevate:not(.no-default-hover-elevate),
|
|
.active-elevate:not(.no-default-active-elevate),
|
|
.hover-elevate-2:not(.no-default-hover-elevate),
|
|
.active-elevate-2:not(.no-default-active-elevate) {
|
|
position: relative;
|
|
z-index: 0;
|
|
}
|
|
|
|
.hover-elevate:not(.no-default-hover-elevate)::after,
|
|
.active-elevate:not(.no-default-active-elevate)::after,
|
|
.hover-elevate-2:not(.no-default-hover-elevate)::after,
|
|
.active-elevate-2:not(.no-default-active-elevate)::after {
|
|
content: "";
|
|
pointer-events: none;
|
|
position: absolute;
|
|
inset: 0px;
|
|
/*border-radius: inherit; match rounded corners */
|
|
border-radius: inherit;
|
|
z-index: 999;
|
|
/* sits in front of content */
|
|
}
|
|
|
|
.hover-elevate:hover:not(.no-default-hover-elevate)::after,
|
|
.active-elevate:active:not(.no-default-active-elevate)::after {
|
|
background-color: var(--elevate-1);
|
|
}
|
|
|
|
.hover-elevate-2:hover:not(.no-default-hover-elevate)::after,
|
|
.active-elevate-2:active:not(.no-default-active-elevate)::after {
|
|
background-color: var(--elevate-2);
|
|
}
|
|
|
|
/* If there's a 1px border, adjust the inset so that it covers that parent's border */
|
|
.border.hover-elevate:not(.no-hover-interaction-elevate)::after,
|
|
.border.active-elevate:not(.no-active-interaction-elevate)::after,
|
|
.border.hover-elevate-2:not(.no-hover-interaction-elevate)::after,
|
|
.border.active-elevate-2:not(.no-active-interaction-elevate)::after,
|
|
.border.hover-elevate:not(.no-hover-interaction-elevate)::after {
|
|
inset: -1px;
|
|
}
|
|
}
|
|
|
|
/* Нижняя панель на мобильном: учёт safe-area inset (паттерн основного клиента) */
|
|
.safe-area-bottom {
|
|
padding-bottom: env(safe-area-inset-bottom, 0);
|
|
}
|
|
|
|
@supports (padding-bottom: env(safe-area-inset-bottom)) {
|
|
.safe-area-bottom {
|
|
padding-bottom: max(12px, env(safe-area-inset-bottom));
|
|
}
|
|
}
|