//////////////////////////////////////////////////////////////////////////////// // A1sCSS - Модуль управления CSS для A1sNoCode // Часть библиотеки A1sCode (a1scode.ru) // Версия: 2.0 // Дата: 2025 //////////////////////////////////////////////////////////////////////////////// #Область ПрограммныйИнтерфейс #Область ПолучениеСтилей // Возвращает полный CSS со всеми современными стилями // Включает базовые стили, компоненты и темы // // Параметры: // ВключитьШрифты - Булево - включить загрузку веб-шрифтов (по умолчанию Истина) // Тема - Строка - название темы: "light", "dark", "auto" (по умолчанию "light") // // Возвращаемое значение: // Строка - полный CSS код, готовый к встраиванию в HTML // Function GetModernCSS(ВключитьШрифты = Истина, Тема = "light") Export CSS = ""; // Базовые стили CSS = CSS + GetBaseStyles(); // Шрифты (опционально) Если ВключитьШрифты Тогда CSS = CSS + GetFontStyles(); КонецЕсли; // Компоненты CSS = CSS + GetComponentStyles(); // Темы CSS = CSS + GetThemeStyles(Тема); // Утилиты CSS = CSS + GetUtilityStyles(); Возврат ""; КонецФункции // Возвращает минимальный CSS для быстрой загрузки // Используется когда нужен только базовый функционал без декоративных элементов // // Возвращаемое значение: // Строка - минимальный CSS код // Function GetMinimalCSS() Export CSS = GetBaseStyles() + Символы.ПС + GetUtilityStyles(); Возврат ""; КонецФункции // Возвращает CSS только для компонентов // Используется когда базовые стили уже загружены // // Возвращаемое значение: // Строка - CSS компонентов // Function GetComponentsCSS() Export CSS = GetComponentStyles(); Возврат ""; КонецФункции #КонецОбласти #Область ЧтениеФайловСтилей // Читает содержимое CSS файла из каталога модуля // // Параметры: // ИмяФайла - Строка - имя файла CSS (например "base.css") // // Возвращаемое значение: // Строка - содержимое файла или пустая строка при ошибке // Function ReadCSSFile(ИмяФайла) Export Попытка // Путь к каталогу модуля (должен быть настроен в конфигурации) ПутьККаталогу = ПолучитьПутьККаталогуМодуля(); // Объединяем путь с именем файла Разделитель = ПолучитьРазделительПути(); Если Прав(ПутьККаталогу, 1) <> Разделитель Тогда ПутьККаталогу = ПутьККаталогу + Разделитель; КонецЕсли; ПолныйПуть = ПутьККаталогу + ИмяФайла; Файл = Новый Файл(ПолныйПуть); Если Файл.Существует() Тогда ТекстовыйДокумент = Новый ТекстовыйДокумент; ТекстовыйДокумент.Прочитать(ПолныйПуть, КодировкаТекста.UTF8); Возврат ТекстовыйДокумент.ПолучитьТекст(); КонецЕсли; Исключение // Логируем ошибку, но не прерываем выполнение Попытка A1sS.Log("A1sCSS.ReadCSSFile: Ошибка чтения файла " + ИмяФайла + ": " + ОписаниеОшибки()); Исключение // Если A1sS недоступен, просто игнорируем КонецПопытки; КонецПопытки; Возврат ""; КонецФункции // Возвращает путь к каталогу модуля A1sCSS // Может быть переопределен через константу или настройки // // Возвращаемое значение: // Строка - путь к каталогу // Function ПолучитьПутьККаталогуМодуля() Export // По умолчанию используем каталог временных файлов ПутьПоУмолчанию = КаталогВременныхФайлов() + "A1sCSS" + ПолучитьРазделительПути(); Путь = ""; // Пытаемся получить значение константы (если она существует) Попытка // Используем метаданные для проверки существования константы //Для Каждого МетаКонстанта Из Метаданные.Константы Цикл // Если МетаКонстанта.Имя = "A1sConst_PathToA1sCSSFolder" Тогда // Try // //Путь = Константы["A1sConst_PathToA1sCSSFolder"].Получить(); // Если НЕ ПустаяСтрока(Путь) Тогда // Возврат Путь; // КонецЕсли; // Except // Возврат Путь; // EndTry; // КонецЕсли; //КонецЦикла; Исключение // Константа не существует или недоступна - используем путь по умолчанию КонецПопытки; Возврат ПутьПоУмолчанию; КонецФункции #КонецОбласти #КонецОбласти #Область СлужебныеПроцедурыИФункции #Область БазовыеСтили Function GetBaseStyles() CSS = " |/* === A1sCode Base Styles === */ | |* { | box-sizing: border-box; | padding: 0; |} | |html { | font-family: 'JetBrains Mono', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; | font-feature-settings: 'kern' 1, 'liga' 1, 'calt' 1; | text-rendering: optimizeLegibility; | max-width: 85%; | margin: auto; | font-size: calc(13.375px + 0.390625vw); | line-height: 1.6; |} | |html, body { | color: #444; | background: #fff; | -webkit-font-smoothing: antialiased; | -moz-osx-font-smoothing: grayscale; |} | |/* Числовые и финансовые данные */ |.financial-data, table, td, th, code, pre, |.price, .amount, .date, [data-numeric] { | font-feature-settings: 'tnum' 1, 'zero' 1, 'ss01' 1, 'ss02' 1; | font-variant-numeric: tabular-nums lining-nums; |} | |/* Flexbox layout для контента и aside */ |flexcontent { | display: flex; | flex-wrap: wrap; | justify-content: center; | padding: 20px; | gap: 20px; |} | |main { | flex: 1; | min-width: 0; | padding: 20px; |} | |aside { | flex: 0 0 300px; | max-width: 300px; | padding: 20px; | border: 1px solid #e5e7eb; | border-radius: 14px; | box-shadow: 0 4px 14px rgba(0, 0, 0, 0.06); | background-color: #f9fafb; |} | |@media (max-width: 900px) { | aside { | flex: 1 1 100%; | max-width: 100%; | } |} | |/* Типографика */ |h1, h2, h3, h4, h5, h6 { | margin: 1.2em 0 0.6em 0; | font-weight: 700; | line-height: 1.3; | text-rendering: optimizeLegibility; |} | |h1 { | font-size: 2rem; | color: #1a1a1a; | border-bottom: 3px solid #ffa34d; | padding-bottom: 0.3em; |} | |h2 { | font-size: 1.6rem; | color: #2d2d2d; | border-bottom: 2px solid #ffc280; | padding-bottom: 0.25em; |} | |h3 { | font-size: 1.3rem; | color: #3d3d3d; |} | |h4 { | font-size: 1.1rem; | color: #4d4d4d; |} | |h5, h6 { | font-size: 1rem; | color: #5d5d5d; |} | |p { | margin: 1em 0; | max-width: 768px; | line-height: 1.7; | word-wrap: break-word; |} | |a { | color: #3b82f6; | text-decoration: none; | transition: all 0.2s ease; |} | |a:hover { | color: #1d4ed8; | text-decoration: underline; |} | |blockquote { | margin: 1.5em 0; | padding: 1em 1.5em; | border-left: 5px solid #ffa34d; | background: rgba(255, 163, 77, 0.05); | color: rgba(0, 0, 0, 0.7); | border-radius: 0 8px 8px 0; |} | |code { | font-family: 'JetBrains Mono', 'Fira Code', Consolas, monospace; | font-size: 0.9em; | background: #fff8ef; | padding: 0.2em 0.4em; | border-radius: 4px; | border: 1px solid #ffe1bf; |} | |pre { | background: #fff8ef; | border: 1px solid #ffe1bf; | border-radius: 8px; | padding: 1em; | overflow-x: auto; | margin: 1.5em 0; |} | |pre code { | background: none; | border: none; | padding: 0; |} | |hr { | border: none; | border-top: 2px solid #e5e7eb; | margin: 2em 0; |} | |strong, b { | color: #ff7d08; | font-weight: 700; | background-color: rgba(255, 125, 8, 0.08); | padding: 0 0.2em; | border-radius: 3px; |} | |em, i { | font-style: italic; | background: #fffbeb; | padding: 0 0.3em; | border-radius: 3px; |} | |/* Списки */ |ul, ol { | margin: 1em 0; | padding-left: 2em; |} | |li { | margin: 0.5em 0; | line-height: 1.6; |} | |/* Таблицы */ |table { | width: 100%; | border-collapse: separate; | border-spacing: 0; | margin: 1.5em 0; | border: 1px solid #e5e7eb; | border-radius: 8px; | overflow: hidden; |} | |th, td { | padding: 0.8em 1em; | text-align: left; | border-bottom: 1px solid #e5e7eb; |} | |th { | background: #f9fafb; | font-weight: 700; | color: #1f2937; |} | |tr:last-child td { | border-bottom: none; |} | |tr:hover { | background: #f9fafb; |}"; Возврат CSS; КонецФункции #КонецОбласти #Область СтилиШрифтов Function GetFontStyles() CSS = " | |/* === Web Fonts === */ | |@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); |@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap'); |@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600&display=swap');"; Возврат CSS; КонецФункции #КонецОбласти #Область СтилиКомпонентов Function GetComponentStyles() CSS = " | |/* === Components === */ | |/* Alerts & Callouts */ |.alert, .callout { | --accent-rgb: 255, 163, 77; | position: relative; | margin: 14px 0; | padding: 12px 14px 12px 16px; | border-radius: 14px; | border: 1px solid rgba(var(--accent-rgb), 0.25); | background: rgba(var(--accent-rgb), 0.06); |} | |.alert::before, .callout::before { | content: ''; | position: absolute; | inset: 0 auto 0 0; | width: 6px; | border-radius: 14px 0 0 14px; | background: linear-gradient(180deg, | rgba(var(--accent-rgb), 0.95), | rgba(var(--accent-rgb), 0.55)); |} | |.alert strong { | font-weight: 700; | margin-right: 0.35rem; |} | |.alert a { | color: rgb(var(--accent-rgb)); | font-weight: 600; | text-decoration: none; | border-radius: 6px; | padding: 1px 3px; |} | |.alert a:hover { | text-decoration: underline; | background: rgba(var(--accent-rgb), 0.10); |} | |/* Alert variants */ |.alert--info, .callout--info { --accent-rgb: 59, 130, 246; } |.alert--warn, .callout--warn { --accent-rgb: 245, 158, 11; } |.alert--success, .callout--ok { --accent-rgb: 16, 185, 129; } |.alert--danger, .callout--danger { --accent-rgb: 239, 68, 68; } | |/* Cards */ |.card, .lib-card, .content-card { | background: #fff; | border: 1px solid #e5e7eb; | border-radius: 14px; | padding: 20px; | margin: 14px 0; | box-shadow: 0 4px 14px rgba(0, 0, 0, 0.06); | transition: transform 0.18s ease, box-shadow 0.18s ease; |} | |.card:hover, .lib-card:hover, .content-card:hover { | transform: translateY(-3px); | box-shadow: 0 12px 28px rgba(0, 0, 0, 0.10); |} | |/* Buttons */ |.btn { | display: inline-block; | padding: 10px 20px; | font-weight: 600; | text-align: center; | border: none; | border-radius: 12px; | cursor: pointer; | transition: transform 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease; | background: linear-gradient(135deg, #ffa34d, #ff7d08); | color: #fff !important; | text-decoration: none; |} | |.btn:hover { | transform: translateY(-1px); | box-shadow: 0 8px 16px rgba(0, 0, 0, 0.12); | filter: brightness(0.98); |} | |.btn:active { | transform: translateY(0); | box-shadow: 0 4px 10px rgba(0, 0, 0, 0.10); | filter: brightness(0.92); |} | |.btn:focus-visible { | outline: 2px solid rgba(255, 163, 77, 0.9); | outline-offset: 2px; |} | |.btn.secondary { | background: #fff; | color: #ff7d08 !important; | border: 1px solid #ffa34d; | box-shadow: none; |} | |.btn.secondary:hover { | background: #fff8ef; |} | |.btn.secondary:hover, |.btn.secondary:active { | filter: none; |} | |/* Pills/Badges */ |.pill, .badge { | display: inline-block; | padding: 4px 12px; | font-size: 0.75rem; | font-weight: 700; | border-radius: 999px; | color: #fff; | background: linear-gradient(45deg, #ffa34d, #ff7d08); | box-shadow: 0 4px 14px rgba(255, 125, 8, 0.35); |} | |/* Chips */ |.chip { | display: inline-flex; | align-items: center; | gap: 6px; | padding: 4px 10px; | border: 1px solid #e5e7eb; | border-radius: 999px; | font-size: 12px; | background: #fff; | font-weight: 500; |} | |/* Grid system */ |.grid { | display: grid; | grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | gap: 20px; | margin: 20px 0; |} | |/* Code highlighting */ |pre.code { | background: #fff8ef; | border: 1px solid #ffe1bf; |} | |pre.code code { | color: #222; |}"; Возврат CSS; КонецФункции #КонецОбласти #Область СтилиТемы Function GetThemeStyles(Тема = "light") Если Тема = "dark" Тогда Возврат GetDarkThemeStyles(); ИначеЕсли Тема = "auto" Тогда Возврат GetAutoThemeStyles(); Иначе Возврат ""; // Светлая тема по умолчанию уже применена КонецЕсли; КонецФункции Function GetDarkThemeStyles() CSS = " | |/* === Dark Theme === */ | |html, body { | color: #e5e7eb; | background: #0f172a; |} | |h1, h2, h3, h4, h5, h6 { | color: #f1f5f9; |} | |a { | color: #60a5fa; |} | |a:hover { | color: #93c5fd; |} | |code, pre { | background: #1e293b; | border-color: #334155; |} | |aside { | background: #1e293b; | border-color: #334155; |} | |.card, .lib-card, .content-card { | background: #1e293b; | border-color: #334155; |} | |table { | border-color: #334155; |} | |th { | background: #1e293b; | color: #f1f5f9; |} | |td { | border-color: #334155; |} | |tr:hover { | background: #1e293b; |}"; Возврат CSS; КонецФункции Function GetAutoThemeStyles() CSS = " | |/* === Auto Theme (respects system preference) === */ | |@media (prefers-color-scheme: dark) { | html, body { | color: #e5e7eb; | background: #0f172a; | } | | h1, h2, h3, h4, h5, h6 { | color: #f1f5f9; | } | | a { | color: #60a5fa; | } | | a:hover { | color: #93c5fd; | } | | code, pre { | background: #1e293b; | border-color: #334155; | } | | aside { | background: #1e293b; | border-color: #334155; | } | | .card, .lib-card, .content-card { | background: #1e293b; | border-color: #334155; | } |}"; Возврат CSS; КонецФункции #КонецОбласти #Область УтилитныеСтили Function GetUtilityStyles() CSS = " | |/* === Utility Classes === */ | |/* Text sizes */ |.text-xs { font-size: 0.75rem; } |.text-sm { font-size: 0.875rem; } |.text-base { font-size: 1rem; } |.text-lg { font-size: 1.125rem; } |.text-xl { font-size: 1.25rem; } |.text-2xl { font-size: 1.5rem; } | |/* Colors */ |.text-primary { color: #ffa34d; } |.text-secondary { color: #6b7280; } |.text-success { color: #10b981; } |.text-warning { color: #f59e0b; } |.text-danger { color: #ef4444; } |.text-info { color: #3b82f6; } | |/* Backgrounds */ |.bg-primary { background-color: #ffa34d; } |.bg-light { background-color: #f9fafb; } |.bg-dark { background-color: #1f2937; } | |/* Spacing */ |.mt-1 { margin-top: 0.5rem; } |.mt-2 { margin-top: 1rem; } |.mt-3 { margin-top: 1.5rem; } |.mt-4 { margin-top: 2rem; } | |.mb-1 { margin-bottom: 0.5rem; } |.mb-2 { margin-bottom: 1rem; } |.mb-3 { margin-bottom: 1.5rem; } |.mb-4 { margin-bottom: 2rem; } | |.p-1 { padding: 0.5rem; } |.p-2 { padding: 1rem; } |.p-3 { padding: 1.5rem; } |.p-4 { padding: 2rem; } | |/* Display */ |.hidden { display: none; } |.block { display: block; } |.inline { display: inline; } |.inline-block { display: inline-block; } |.flex { display: flex; } |.grid { display: grid; } | |/* Text alignment */ |.text-left { text-align: left; } |.text-center { text-align: center; } |.text-right { text-align: right; } | |/* Font weight */ |.font-normal { font-weight: 400; } |.font-medium { font-weight: 500; } |.font-semibold { font-weight: 600; } |.font-bold { font-weight: 700; } | |/* Focus & accessibility */ |a:focus-visible, |.btn:focus-visible, |button:focus-visible { | outline: 2px solid #94a3b8; | outline-offset: 3px; | border-radius: 6px; |}"; Возврат CSS; КонецФункции #КонецОбласти #КонецОбласти