Bladeren bron

restart projeckt

Gogs 3 weken geleden
bovenliggende
commit
88b26aa0a6
4 gewijzigde bestanden met toevoegingen van 472 en 633 verwijderingen
  1. 47 11
      README.md
  2. 179 113
      app/index.coffee
  3. 35 44
      app/index.pug
  4. 211 465
      app/index.styl

+ 47 - 11
README.md

@@ -199,6 +199,9 @@ div(class="app" :class="{'theme-dark': theme === 'dark'}")
 
 **app/index.coffee**
 ```coffee
+# Глобальная инициализация debug в начале файла, сам debug уже глобально определён
+globalThis.log = debug.log
+
 # Загрузка конфигурации
 config = require 'app/config'
 DataTypes = require 'app/types/data'
@@ -208,9 +211,6 @@ EventTypes = require 'app/types/events'
 globalThis.renderFns = require 'pug.json'
 globalThis.stylFns = require 'styl.json'
 
-# Глобальная инициализация debug
-globalThis.debug = require 'debug'
-globalThis.log = debug.log
 
 # Сервисы
 PouchDBService = require 'app/utils/pouch'
@@ -280,7 +280,7 @@ app = Vue.createApp({
         ), 300
       ), 5000
   
-  async mounted: ->
+  mounted: -> # не используй async  в определении методов и обработчиков событий
     # Инициализация темы
     if @theme == 'dark'
       document.documentElement.classList.add 'dark'
@@ -917,7 +917,10 @@ importFromCSV: (file, domain, onProgress) ->
 ## 📊 ТЕКУЩОЕ СОСТОЯНИЕ ПРОЕКТА
 
 ### ✅ ВЫПОЛНЕНО
-
+1. **Базовая архитектура** 
+   - Напиши базовые файлы системы
+   - Система роутинга
+   - Глобальная конфигурация
 
 ### 🎯 БЛИЖАЙШИЕ ЗАДАЧИ
 
@@ -960,11 +963,44 @@ importFromCSV: (file, domain, onProgress) ->
 ### 🔄 В РАБОТЕ СЕЙЧАС
 
 отвечай на русском Анализировать реализованный код, по git репозитарию https://gogs.osvoj.ru/oleg/s5l.ru-crm.git Проверяй промт и изменения в нём по адресу https://gogs.osvoj.ru/oleg/s5l.ru-crm/raw/master/README.md
+  после выполнения задачи, напиши
+   - что сделано.
+   - Напиши следущую задачу на выполнение (после завершения отладки, созданых файлов)
 
-Заново начни разработку проекта. создай первые необходимые файлы.
 
-1. **Базовая архитектура**  ⚠️ ПРИОРИТЕТ
-   - Напиши базовые файлы системы
-   - Система роутинга
-   - Глобальная конфигурация
-   - Напиши следущую задачу на выполнение (после завершения отладки, созданых файлов)
+ЭТАП 1.2: СИСТЕМА РОУТИНГА И БАЗОВЫЕ СТРАНИЦЫ  ⚠️ ПРИОРИТЕТ
+    Создать Vue Router конфигурацию
+    
+    Файл маршрутизации с основными путями
+    
+    Обработка динамических доменов
+    
+    Middleware для проверки прав доступа
+    
+    Создать базовые страницы:
+    
+    Главная страница (/)
+    
+    Страница 404 (/*)
+    
+    Заглушки для основных разделов
+    
+    Разработать базовые UI компоненты:
+    
+    Кнопка (Button)
+    
+    Модальное окно (Modal)
+    
+    Уведомления (Notification)
+    
+    Индикатор загрузки (Loader)
+    
+    Настроить PouchDB сервис:
+    
+    Подключение к CouchDB
+    
+    Дизайн-документы
+    
+    Система синхронизации
+    
+    Приоритет: Высокий ⚠️

+ 179 - 113
app/index.coffee

@@ -1,154 +1,220 @@
+# Глобальная инициализация debug
+globalThis.log = debug.log
+
+# Главный файл приложения
+log '🚀 Инициализация приложения Браер-Колор'
+
+# Загрузка конфигурации
+config = require 'app/config'
+DataTypes = require 'app/types/data'
+EventTypes = require 'app/types/events'
+
 # Инициализация глобальных переменных
 globalThis.renderFns = require 'pug.json'
 globalThis.stylFns = require 'styl.json'
 
 
-PouchDBService = require 'app/utils/pouch.coffee'
-
-# Инициализация сервиса данных
-pouchService = PouchDBService
 
-document.head.insertAdjacentHTML 'beforeend','<meta charset="UTF-8">'
-document.head.insertAdjacentHTML 'beforeend','<meta name="viewport" content="width=device-width, initial-scale=1.0">'
+# Сервисы (пока заглушки)
+PouchDBService = 
+  init: -> Promise.resolve()
+  getDocument: -> Promise.resolve(null)
+  saveToRemote: -> Promise.resolve()
 
+DomainService = 
+  init: -> Promise.resolve()
+  loadDomainSettings: -> Promise.resolve(null)
+  getAvailableDomains: -> []
 
-document.head.insertAdjacentHTML('beforeend','<style  type="text/css">'+stylFns['app/index.styl']+'</style>')
+# Мета-теги
+document.head.insertAdjacentHTML 'beforeend', '<meta charset="UTF-8">'
+document.head.insertAdjacentHTML 'beforeend', '<meta name="viewport" content="width=device-width, initial-scale=1.0">'
+document.head.insertAdjacentHTML 'beforeend', '<title>Браер-Колор - Интернет-магазин лакокрасочной продукции</title>'
 
-document.head.insertAdjacentHTML('beforeend','<title></title>')
+# Добавление глобальных стилей
+if stylFns['app/index.styl']
+  styleElement = document.createElement('style')
+  styleElement.type = 'text/css'
+  styleElement.textContent = stylFns['app/index.styl']
+  document.head.appendChild(styleElement)
+else
+  log '⚠️ Глобальные стили не найдены'
 
-
-# Создание главного приложения Vue
+# Создание Vue приложения
 app = Vue.createApp({
   data: ->
-    return {
-      theme: localStorage.getItem('theme') || 'light'
-      companyName: 'Браер-Колор'
+    {
+      theme: localStorage.getItem('theme') or config.defaultTheme
+      companyName: config.companyName
       loading: false
-      cartItems: []
-      user: null
       currentDomain: window.location.hostname
-      languages: ['ru', 'en']
-      currentLanguage: 'ru'
       currentDomainSettings: null
+      availableDomains: []
+      languages: config.languages
+      currentLanguage: localStorage.getItem('language') or config.defaultLanguage
+      user: null
+      cartItems: []
+      notifications: []
     }
   
-  render: (new Function '_ctx', '_cache', renderFns['app/index.pug'])()
-  
   computed:
-    isAdmin: -> @user?.role == 'admin'
+    isAdmin: -> 
+      @user?.role == 'admin'
+    
+    domainConfig: -> 
+      DomainService.getDomainConfig?(@currentDomain) or {}
   
   methods:
+    # Управление темой
     toggleTheme: ->
       @theme = if @theme == 'light' then 'dark' else 'light'
       localStorage.setItem 'theme', @theme
       document.documentElement.classList.toggle 'dark'
+      @$emit EventTypes.THEME_CHANGED, @theme
+      log '🎨 Тема изменена:', @theme
     
+    # Управление языком
     setLanguage: (lang) ->
       if @languages.includes lang
         @currentLanguage = lang
-        localStorage.setItem 'language', @lang
+        localStorage.setItem 'language', @currentLanguage
+        @$emit EventTypes.LANGUAGE_CHANGED, lang
+        log '🌐 Язык изменен:', lang
+      else
+        log '⚠️ Язык не поддерживается:', lang
     
-    loadDomainSettings: ->
-      pouchService.getDocument("domain_settings:#{@currentDomain}")
+    # Загрузка настроек домена
+    loadDomainData: ->
+      log '📡 Загрузка настроек домена:', @currentDomain
+      
+      DomainService.loadDomainSettings(@currentDomain)
         .then (settings) =>
           @currentDomainSettings = settings
-          # Устанавливаем заголовок страницы
-          if settings?.companyName
-            document.title = settings.companyName
+          document.title = settings?.companyName or @companyName
+          log '✅ Настройки домена загружены', settings
         .catch (error) =>
-          debug.log 'Настройки домена не найдены, используются значения по умолчанию'
-          @currentDomainSettings = null
+          log '⚠️ Настройки домена не найдены, используются значения по умолчанию'
+          @currentDomainSettings = new DataTypes.DomainSettings()
+          @currentDomainSettings.companyName = @companyName
     
-    showNotification: (message, type = 'success') ->
-      # Реализация системы уведомлений
-      debug.log "#{type.toUpperCase()}: #{message}"
-  
-  mounted: ->
-    # Инициализация темы
-    if @theme == 'dark'
-      document.documentElement.classList.add 'dark'
+    # Управление корзиной
+    updateCart: (items) ->
+      @cartItems = items
+      localStorage.setItem 'cart', JSON.stringify(items)
+      @$emit EventTypes.CART_UPDATE, items
+      log '🛒 Корзина обновлена:', items.length, 'товаров'
     
-    # Инициализация PouchDB
-    try
-      await pouchService.init()
-      debug.log 'PouchDB инициализирован'
-      # Загружаем настройки домена
-      await @loadDomainSettings()
-    catch error
-      console.error 'Ошибка инициализации PouchDB:', error
+    # Уведомления
+    showNotification: (message, type = 'info') ->
+      notification = { 
+        id: Date.now(), 
+        message, 
+        type, 
+        visible: true,
+        timestamp: new Date()
+      }
+      
+      @notifications.push notification
+      log '📢 Показано уведомление:', message
+      
+      setTimeout (=>
+        notification.visible = false
+        setTimeout (=>
+          @notifications = @notifications.filter (n) -> n.id != notification.id
+        ), 300
+      ), 5000
     
-    # Загрузка пользователя (если авторизован)
-    @loadUserData()
-  
-  loadUserData: ->
-    # Загрузка данных пользователя из localStorage или PouchDB
-    userData = localStorage.getItem 'user'
-    if userData
-      try
-        @user = JSON.parse userData
-      catch
+    # Загрузка пользователя
+    loadUserData: ->
+      userData = localStorage.getItem 'user'
+      if userData
+        try
+          @user = JSON.parse userData
+          log '👤 Пользователь загружен:', @user.username
+        catch error
+          log '❌ Ошибка загрузки пользователя:', error
+          @user = null
+      else
         @user = null
+    
+    # Загрузка корзины
+    loadCartData: ->
+      cartData = localStorage.getItem 'cart'
+      if cartData
+        try
+          @cartItems = JSON.parse cartData
+          log '🛒 Корзина загружена:', @cartItems.length, 'товаров'
+        catch error
+          log '❌ Ошибка загрузки корзины:', error
+          @cartItems = []
+      else
+        @cartItems = []
+    
+    # Инициализация приложения
+    initializeApp: ->
+      log '🔧 Начало инициализации приложения'
+      @loading = true
+      
+      # Инициализация темы
+      if @theme == 'dark'
+        document.documentElement.classList.add 'dark'
+        log '🌙 Темная тема активирована'
+      else
+        log '☀️ Светлая тема активирована'
+      
+      # Последовательная инициализация сервисов
+      Promise.resolve()
+        .then =>
+          log '📦 Инициализация PouchDB...'
+          PouchDBService.init()
+        .then =>
+          log '🌐 Инициализация DomainService...'
+          DomainService.init()
+        .then =>
+          log '📡 Получение доступных доменов...'
+          @availableDomains = DomainService.getAvailableDomains()
+        .then =>
+          @loadDomainData()
+        .then =>
+          @loadUserData()
+        .then =>
+          @loadCartData()
+        .then =>
+          log '✅ Приложение успешно инициализировано'
+          @showNotification('Приложение готово к работе', 'success')
+        .catch (error) =>
+          log '❌ Ошибка инициализации приложения:', error
+          @showNotification('Ошибка загрузки приложения', 'error')
+        .finally =>
+          @loading = false
+  
+  mounted: ->
+    await @initializeApp()
+  
+  # Рендер функция из Pug
+  render: (new Function '_ctx', '_cache', renderFns['app/index.pug'])()
 })
 
-
-
-# Настройка маршрутизатора
-router = VueRouter.createRouter({
-  history: VueRouter.createWebHistory()
-  routes: [
-    { path: '/', component: require 'app/pages/Home' },
-    { 
-      path: '/admin',
-      component: require 'app/pages/Admin'
-      meta: { requiresAdmin: true }
-      redirect: '/admin/settings'
-      children: [
-        { path: 'slider', component: require 'app/pages/Admin/Slider' }
-        { path: 'products', component: require 'app/pages/Admin/Products' }
-        #{ path: 'clients', component: require 'app/pages/Admin/Clients' }
-        { path: 'blog', component: require 'app/pages/Admin/Blog' }
-        #{ path: 'routes', component: require 'app/pages/Admin/Routes' }
-        { path: 'settings', component: require 'app/pages/Admin/Settings' }
-      ]
-    },
-    #{ path: '/catalog', component: require 'app/pages/Catalog' },
-    #{ path: '/blog/:slug', component: require 'app/pages/BlogArticle' },
-    #{ path: '/contacts', component: require 'app/pages/Contacts' },
-    #{ path: '/about', component: require 'app/pages/About' }
-  ]
-})
-
-# Глобальный навигационный хук
-#router.beforeEach (to, from, next) ->
-#  if to.meta.requiresAdmin
-#    userData = localStorage.getItem 'user'
-#    if userData
-#      try
-#        user = JSON.parse userData
-#        if user.role == 'admin'
-#          next()
-#        else
-#          next('/')
-#      catch
-#        next('/')
-#    else
-#      next('/')
-#  else
-#    next()
-
-app.use(router)
-
-# Глобальная обработка ошибок
+# Глобальная обработка ошибок Vue
 app.config.errorHandler = (err, vm, info) ->
-  console.error 'Vue Error:', err
-  console.error 'Component:', vm
-  console.error 'Info:', info
-  
-  # В продакшне отправлять ошибки на сервер
-  if process.env.NODE_ENV != 'production'
-    vm?.$root?.showNotification?('Произошла ошибка приложения', 'error')
+  log '💥 Vue ошибка:', err, info
+  console.error('Vue ошибка:', err, info)
+
+# Глобальная обработка предупреждений
+app.config.warnHandler = (msg, vm, trace) ->
+  log '⚠️ Vue предупреждение:', msg, trace
+
+# Регистрация глобальных компонентов (заглушки)
+app.component('RouterView', { template: '<div>Router View</div>' })
+app.component('RouterLink', { 
+  props: ['to'],
+  template: '<a :href="to"><slot></slot></a>'
+})
 
 # Монтирование приложения
-app.mount('body')
-
-debug.log 'Приложение Браер-Колор инициализировано'
+try
+  app.mount('body')
+  log '✅ Приложение успешно смонтировано'
+catch error
+  log '❌ Ошибка монтирования приложения:', error
+  console.error('Ошибка монтирования:', error)

+ 35 - 44
app/index.pug

@@ -1,47 +1,38 @@
-div(id="app")
-  // Единый header для всего приложения
+//- Главный layout приложения
+div(class="app" :class="{'theme-dark': theme === 'dark'}")
   header(class="header")
-    nav(class="header__nav")
-      div(class="header__nav-block")
-        div(class="header__brand")
-          img(
-            v-if="currentDomainSettings && currentDomainSettings.logo"
-            :src="currentDomainSettings.logo" 
-            :alt="currentDomainSettings.companyName || 'Браер-Колор'"
-            class="header__logo"
-          )
-          span(v-else class="header__nav-name") {{ companyName }}
-        div(class="header__nav-menu")
-          div(class="header__menu-item")
-            router-link(to="/catalog" class="header__menu-link") Каталог
-          div(class="header__menu-item")
-            router-link(to="/blog" class="header__menu-link") Блог
-          div(class="header__menu-item")
-            router-link(to="/contacts" class="header__menu-link") Контакты
-          div(class="header__menu-item")
-            button(
-              @click="toggleTheme"
-              class="header__theme-toggle"
-            ) {{ theme === 'light' ? '🌙' : '☀️' }}
+    nav(class="header-nav")
+      div(class="header-nav-block")
+        div(class="header-nav--name") {{ currentDomainSettings?.companyName || companyName }}
+        div(class="header-nav--menu")
+          //- TODO: Добавить компоненты
+          //- multilevelmenu(:domains="availableDomains" :current-domain="currentDomain")
+          //- themetoggle(:theme="theme" @theme-changed="toggleTheme")
+          //- languagetoggle(:languages="languages" :current-language="currentLanguage" @language-changed="setLanguage")
+          //- cartwidget(:items="cartItems" @update-cart="updateCart")
+          
+          //- Временные элементы
+          button(@click="toggleTheme" class="btn btn-sm") 
+            span(v-if="theme === 'light'") 🌙
+            span(v-else) ☀️
+          
+          span(class="badge") {{ currentLanguage }}
+          
+          button(@click="showNotification('Тестовое уведомление')" class="btn btn-sm") 
+            | 🔔
   
-  main(class="main")
-    router-view(v-slot='{ Component }')
-      transition(name='page-slide' mode='out-in')
-        component(:is='Component')
+  main(class="main-content")
+    router-view(v-slot="{ Component, route }")
+      transition(name="page-slide" mode="out-in")
+        component(
+          :is="Component"
+          :key="route.fullPath"
+          :domain-settings="currentDomainSettings"
+          :language="currentLanguage"
+        )
   
-  footer(class="footer")
-    div(class="footer__content")
-      div(class="footer__sections")
-        div(class="footer__section")
-          h3(class="footer__section-title") {{ currentDomainSettings?.companyName || companyName }}
-          p(class="footer__section-text") {{ currentDomainSettings?.description || 'Интернет-магазин лакокрасочной продукции' }}
-        div(class="footer__section")
-          h3(class="footer__section-title") Контакты
-          p(class="footer__section-text") {{ currentDomainSettings?.email || 'info@braer-color.ru' }}
-          p(class="footer__section-text") {{ currentDomainSettings?.phone || '+7 (999) 999-99-99' }}
-        div(class="footer__section")
-          h3(class="footer__section-title") Быстрые ссылки
-          div(class="footer__links")
-            router-link(to="/catalog" class="footer__link") Каталог
-            router-link(to="/blog" class="footer__link") Блог
-            router-link(to="/about" class="footer__link") О компании
+  //- TODO: Добавить компонент уведомлений
+  //- notification-container(:notifications="notifications")
+  
+  div(v-if="loading" class="loading-overlay")
+    div(class="loading-spinner") Загрузка...

+ 211 - 465
app/index.styl

@@ -1,505 +1,251 @@
-// Базовые цвета
-$primary-50 = #fef2f2
-$primary-100 = #fee2e2
-$primary-200 = #fecaca
-$primary-300 = #fca5a5
-$primary-400 = #f87171
-$primary-500 = #ef4444
-$primary-600 = #dc2626
-$primary-700 = #b91c1c
-$primary-800 = #991b1b
-$primary-900 = #7f1d1d
-
-$accent-50 = #f0f9ff
-$accent-100 = #e0f2fe
-$accent-200 = #bae6fd
-$accent-300 = #7dd3fc
-$accent-400 = #38bdf8
-$accent-500 = #0ea5e9
-$accent-600 = #0284c7
-$accent-700 = #0369a1
-$accent-800 = #075985
-$accent-900 = #0c4a6e
-
-$gray-50 = #f9fafb
-$gray-100 = #f3f4f6
-$gray-200 = #e5e7eb
-$gray-300 = #d1d5db
-$gray-400 = #9ca3af
-$gray-500 = #6b7280
-$gray-600 = #4b5563
-$gray-700 = #374151
-$gray-800 = #1f2937
-$gray-900 = #111827
-
-$white = #ffffff
-$black = #000000
-
-// CSS-переменные для глобального использования
+// CSS переменные вместо rgba функций
 :root
   // Основные цвета
-  --color-primary-50: #fef2f2
-  --color-primary-100: #fee2e2
-  --color-primary-200: #fecaca
-  --color-primary-300: #fca5a5
-  --color-primary-400: #f87171
-  --color-primary-500: #ef4444
-  --color-primary-600: #dc2626
-  --color-primary-700: #b91c1c
-  --color-primary-800: #991b1b
-  --color-primary-900: #7f1d1d
-
-  --color-accent-50: #f0f9ff
-  --color-accent-100: #e0f2fe
-  --color-accent-200: #bae6fd
-  --color-accent-300: #7dd3fc
-  --color-accent-400: #38bdf8
-  --color-accent-500: #0ea5e9
-  --color-accent-600: #0284c7
-  --color-accent-700: #0369a1
-  --color-accent-800: #075985
-  --color-accent-900: #0c4a6e
-
-  --color-gray-50: #f9fafb
-  --color-gray-100: #f3f4f6
-  --color-gray-200: #e5e7eb
-  --color-gray-300: #d1d5db
-  --color-gray-400: #9ca3af
-  --color-gray-500: #6b7280
-  --color-gray-600: #4b5563
-  --color-gray-700: #374151
-  --color-gray-800: #1f2937
-  --color-gray-900: #111827
-
+  --color-primary: #2c5aa0
+  --color-secondary: #6c757d
+  --color-success: #28a745
+  --color-danger: #dc3545
+  --color-warning: #ffc107
+  --color-info: #17a2b8
+  --color-light: #f8f9fa
+  --color-dark: #343a40
   --color-white: #ffffff
   --color-black: #000000
+  
+  // Прозрачные варианты
+  --color-primary-10: #2c5aa01a
+  --color-primary-20: #2c5aa033
+  --color-primary-50: #2c5aa080
+  --color-dark-10: #343a401a
+  --color-dark-20: #343a4033
+  --color-dark-50: #343a4080
+  --color-dark-80: #343a40cc
+  --color-light-10: #f8f9fa1a
+  --color-light-50: #f8f9fa80
+  --color-light-80: #f8f9facc
+  
+  // Тени
+  --shadow-sm: 0 1px 2px var(--color-dark-10)
+  --shadow-md: 0 4px 6px var(--color-dark-10)
+  --shadow-lg: 0 10px 15px var(--color-dark-10)
+  --shadow-xl: 0 20px 25px var(--color-dark-10)
+  
+  // Границы
+  --border-radius: 8px
+  --border-radius-sm: 4px
+  --border-radius-lg: 12px
+  --border-width: 1px
+  --border-color: var(--color-dark-10)
+  
+  // Типографика
+  --font-family: 'Inter', 'Segoe UI', system-ui, sans-serif
+  --font-size-xs: 0.75rem
+  --font-size-sm: 0.875rem
+  --font-size-base: 1rem
+  --font-size-lg: 1.125rem
+  --font-size-xl: 1.25rem
+  --font-size-2xl: 1.5rem
+  --font-size-3xl: 1.875rem
+  --font-weight-light: 300
+  --font-weight-normal: 400
+  --font-weight-medium: 500
+  --font-weight-semibold: 600
+  --font-weight-bold: 700
+  --line-height-tight: 1.25
+  --line-height-normal: 1.5
+  --line-height-relaxed: 1.75
+  
+  // Отступы
+  --spacing-xs: 0.25rem
+  --spacing-sm: 0.5rem
+  --spacing-md: 1rem
+  --spacing-lg: 1.5rem
+  --spacing-xl: 2rem
+  --spacing-2xl: 3rem
+  
+  // Транзишены
+  --transition-fast: all 0.15s ease
+  --transition-normal: all 0.3s ease
+  --transition-slow: all 0.5s ease
+  
+  // Z-индексы
+  --z-dropdown: 1000
+  --z-sticky: 1020
+  --z-fixed: 1030
+  --z-modal-backdrop: 1040
+  --z-modal: 1050
+  --z-popover: 1060
+  --z-tooltip: 1070
+  --z-notification: 1080
 
-  // RGB значения для использования с прозрачностью
-  --color-primary-500-rgb: 239, 68, 68
-  --color-primary-600-rgb: 220, 38, 38
-  --color-accent-500-rgb: 14, 165, 233
-  --color-accent-600-rgb: 2, 132, 199
-  --color-gray-500-rgb: 107, 114, 128
-  --color-gray-600-rgb: 75, 85, 99
-  --color-gray-700-rgb: 55, 65, 81
-  --color-gray-800-rgb: 31, 41, 55
-  --color-gray-900-rgb: 17, 24, 39
-  --color-white-rgb: 255, 255, 255
-  --color-black-rgb: 0, 0, 0
-
-  // Готовые цвета с прозрачностью
-  // Primary colors with opacity
-  --color-primary-50-a10: rgba(254, 242, 242, 0.1)
-  --color-primary-50-a20: rgba(254, 242, 242, 0.2)
-  --color-primary-50-a30: rgba(254, 242, 242, 0.3)
-  --color-primary-50-a40: rgba(254, 242, 242, 0.4)
-  --color-primary-50-a50: rgba(254, 242, 242, 0.5)
-
-  --color-primary-500-a10: rgba(239, 68, 68, 0.1)
-  --color-primary-500-a20: rgba(239, 68, 68, 0.2)
-  --color-primary-500-a30: rgba(239, 68, 68, 0.3)
-  --color-primary-500-a40: rgba(239, 68, 68, 0.4)
-  --color-primary-500-a50: rgba(239, 68, 68, 0.5)
-  --color-primary-500-a60: rgba(239, 68, 68, 0.6)
-  --color-primary-500-a70: rgba(239, 68, 68, 0.7)
-  --color-primary-500-a80: rgba(239, 68, 68, 0.8)
-  --color-primary-500-a90: rgba(239, 68, 68, 0.9)
-
-  --color-primary-600-a10: rgba(220, 38, 38, 0.1)
-  --color-primary-600-a20: rgba(220, 38, 38, 0.2)
-  --color-primary-600-a30: rgba(220, 38, 38, 0.3)
-  --color-primary-600-a40: rgba(220, 38, 38, 0.4)
-  --color-primary-600-a50: rgba(220, 38, 38, 0.5)
-
-  // Accent colors with opacity
-  --color-accent-500-a10: rgba(14, 165, 233, 0.1)
-  --color-accent-500-a20: rgba(14, 165, 233, 0.2)
-  --color-accent-500-a30: rgba(14, 165, 233, 0.3)
-  --color-accent-500-a40: rgba(14, 165, 233, 0.4)
-  --color-accent-500-a50: rgba(14, 165, 233, 0.5)
-  --color-accent-500-a60: rgba(14, 165, 233, 0.6)
-  --color-accent-500-a70: rgba(14, 165, 233, 0.7)
-  --color-accent-500-a80: rgba(14, 165, 233, 0.8)
-  --color-accent-500-a90: rgba(14, 165, 233, 0.9)
-
-  --color-accent-600-a10: rgba(2, 132, 199, 0.1)
-  --color-accent-600-a20: rgba(2, 132, 199, 0.2)
-  --color-accent-600-a30: rgba(2, 132, 199, 0.3)
-  --color-accent-600-a40: rgba(2, 132, 199, 0.4)
-  --color-accent-600-a50: rgba(2, 132, 199, 0.5)
-
-  // Gray colors with opacity
-  --color-gray-500-a10: rgba(107, 114, 128, 0.1)
-  --color-gray-500-a20: rgba(107, 114, 128, 0.2)
-  --color-gray-500-a30: rgba(107, 114, 128, 0.3)
-  --color-gray-500-a40: rgba(107, 114, 128, 0.4)
-  --color-gray-500-a50: rgba(107, 114, 128, 0.5)
-
-  --color-gray-600-a10: rgba(75, 85, 99, 0.1)
-  --color-gray-600-a20: rgba(75, 85, 99, 0.2)
-  --color-gray-600-a30: rgba(75, 85, 99, 0.3)
-  --color-gray-600-a40: rgba(75, 85, 99, 0.4)
-  --color-gray-600-a50: rgba(75, 85, 99, 0.5)
-
-  --color-gray-700-a10: rgba(55, 65, 81, 0.1)
-  --color-gray-700-a20: rgba(55, 65, 81, 0.2)
-  --color-gray-700-a30: rgba(55, 65, 81, 0.3)
-  --color-gray-700-a40: rgba(55, 65, 81, 0.4)
-  --color-gray-700-a50: rgba(55, 65, 81, 0.5)
-  --color-gray-700-a60: rgba(55, 65, 81, 0.6)
-  --color-gray-700-a70: rgba(55, 65, 81, 0.7)
-  --color-gray-700-a80: rgba(55, 65, 81, 0.8)
-  --color-gray-700-a90: rgba(55, 65, 81, 0.9)
-
-  --color-gray-800-a10: rgba(31, 41, 55, 0.1)
-  --color-gray-800-a20: rgba(31, 41, 55, 0.2)
-  --color-gray-800-a30: rgba(31, 41, 55, 0.3)
-  --color-gray-800-a40: rgba(31, 41, 55, 0.4)
-  --color-gray-800-a50: rgba(31, 41, 55, 0.5)
-  --color-gray-800-a60: rgba(31, 41, 55, 0.6)
-  --color-gray-800-a70: rgba(31, 41, 55, 0.7)
-  --color-gray-800-a80: rgba(31, 41, 55, 0.8)
-  --color-gray-800-a90: rgba(31, 41, 55, 0.9)
-
-  --color-gray-900-a10: rgba(17, 24, 39, 0.1)
-  --color-gray-900-a20: rgba(17, 24, 39, 0.2)
-  --color-gray-900-a30: rgba(17, 24, 39, 0.3)
-  --color-gray-900-a40: rgba(17, 24, 39, 0.4)
-  --color-gray-900-a50: rgba(17, 24, 39, 0.5)
-  --color-gray-900-a60: rgba(17, 24, 39, 0.6)
-  --color-gray-900-a70: rgba(17, 24, 39, 0.7)
-  --color-gray-900-a80: rgba(17, 24, 39, 0.8)
-  --color-gray-900-a90: rgba(17, 24, 39, 0.9)
-
-  // White and black with opacity
-  --color-white-a10: rgba(255, 255, 255, 0.1)
-  --color-white-a20: rgba(255, 255, 255, 0.2)
-  --color-white-a30: rgba(255, 255, 255, 0.3)
-  --color-white-a40: rgba(255, 255, 255, 0.4)
-  --color-white-a50: rgba(255, 255, 255, 0.5)
-  --color-white-a60: rgba(255, 255, 255, 0.6)
-  --color-white-a70: rgba(255, 255, 255, 0.7)
-  --color-white-a80: rgba(255, 255, 255, 0.8)
-  --color-white-a90: rgba(255, 255, 255, 0.9)
-
-  --color-black-a10: rgba(0, 0, 0, 0.1)
-  --color-black-a20: rgba(0, 0, 0, 0.2)
-  --color-black-a30: rgba(0, 0, 0, 0.3)
-  --color-black-a40: rgba(0, 0, 0, 0.4)
-  --color-black-a50: rgba(0, 0, 0, 0.5)
-  --color-black-a60: rgba(0, 0, 0, 0.6)
-  --color-black-a70: rgba(0, 0, 0, 0.7)
-  --color-black-a80: rgba(0, 0, 0, 0.8)
-  --color-black-a90: rgba(0, 0, 0, 0.9)
-
-  // Семантические переменные с прозрачностью
-  --color-background-overlay: var(--color-black-a50)
-  --color-background-modal: var(--color-white-a95)
-  --color-background-tooltip: var(--color-gray-900-a90)
-  --color-background-hover: var(--color-gray-500-a10)
-  --color-background-active: var(--color-primary-500-a20)
-  --color-border-light: var(--color-gray-300-a30)
-  --color-border-medium: var(--color-gray-500-a40)
-  --color-text-secondary: var(--color-gray-600-a80)
-  --color-text-disabled: var(--color-gray-500-a50)
-  --color-shadow-light: var(--color-black-a10)
-  --color-shadow-medium: var(--color-black-a20)
-  --color-shadow-heavy: var(--color-black-a30)
-
-  // Переменные для темной темы с прозрачностью
-  --color-dark-background-overlay: var(--color-white-a10)
-  --color-dark-background-modal: var(--color-gray-900-a95)
-  --color-dark-background-tooltip: var(--color-white-a90)
-  --color-dark-background-hover: var(--color-white-a10)
-  --color-dark-background-active: var(--color-accent-500-a20)
-  --color-dark-border-light: var(--color-white-a20)
-  --color-dark-border-medium: var(--color-white-a30)
+// Темная тема
+.dark
+  --color-light: #343a40
+  --color-dark: #f8f9fa
+  --color-white: #1a1a1a
+  --color-black: #ffffff
+  --color-dark-10: #f8f9fa1a
+  --color-dark-50: #f8f9fa80
+  --color-light-10: #343a401a
+  --color-light-50: #343a4080
+
+// Базовые сбросы
+*, *::before, *::after
+  box-sizing: border-box
+  margin: 0
+  padding: 0
+
+html
+  font-size: 16px
+  line-height: var(--line-height-normal)
+  -webkit-text-size-adjust: 100%
+  -webkit-tap-highlight-color: transparent
+
+body
+  font-family: var(--font-family)
+  font-weight: var(--font-weight-normal)
+  color: var(--color-dark)
+  background-color: var(--color-light)
+  transition: var(--transition-normal)
+  min-height: 100vh
 
-// Миксины
-flex-center()
+// Базовые стили приложения
+.app
+  min-height: 100vh
   display: flex
-  align-items: center
-  justify-content: center
+  flex-direction: column
+  transition: var(--transition-normal)
+  background: var(--color-light)
+  color: var(--color-dark)
 
-flex-between()
+  &.theme-dark
+    background: var(--color-dark)
+    color: var(--color-light)
+
+// Хедер
+.header
   display: flex
   align-items: center
   justify-content: space-between
-
-transition-all($duration = 0.3s)
-  transition: all $duration ease-in-out
-
-// Базовые стили
-#app
-  min-height: 100vh
-  background-color: $white
-  &.dark
-    background-color: $gray-900
-  transition: background-color 0.3s ease-in-out
-
-// Header
-.header
-  background-color: $white
-  box-shadow: 0 1px 3px 0 var(--color-shadow-light)
+  padding: var(--spacing-md) var(--spacing-xl)
+  background: var(--color-light)
+  box-shadow: var(--shadow-sm)
+  border-bottom: var(--border-width) solid var(--border-color)
   position: sticky
   top: 0
-  z-index: 50
-
-  .dark &
-    background-color: $gray-800
-
-.header__nav
-  max-width: 1200px
-  margin: 0 auto
-  padding: 0.75rem 1rem
-
-.header__nav-block
-  flex-between()
+  z-index: var(--z-sticky)
+  
+  .theme-dark &
+    background: var(--color-dark)
+    box-shadow: var(--shadow-md)
 
-.header__brand
+.header-nav
   display: flex
   align-items: center
-  gap: 0.75rem
+  gap: var(--spacing-lg)
 
-.header__logo
-  height: 5rem
-  object-fit: contain
-
-.header__nav-name
-  font-size: 1.5rem
-  font-weight: bold
-  color: $gray-900
-
-  .dark &
-    color: $white
-
-.header__nav-menu
+.header-nav-block
   display: flex
   align-items: center
-  gap: 1rem
+  gap: var(--spacing-md)
 
-.header__menu-item
+.header-nav--name
+  font-size: var(--font-size-xl)
+  font-weight: var(--font-weight-bold)
+  color: var(--color-primary)
+
+.header-nav--menu
   display: flex
   align-items: center
+  gap: var(--spacing-sm)
 
-.header__menu-link
-  color: $gray-600
-  transition: color 0.2s ease-in-out
-  text-decoration: none
-
-  &:hover
-    color: $primary-500
-
-  .dark &
-    color: $gray-300
-
-    &:hover
-      color: $primary-500
-
-.header__theme-toggle
-  padding: 0.5rem
-  border-radius: 0.5rem
-  background-color: $gray-100
-  color: $gray-600
-  transition: all 0.2s ease-in-out
-  border: none
-  cursor: pointer
-
-  &:hover
-    background-color: var(--color-background-hover)
-
-  .dark &
-    background-color: $gray-700
-    color: $gray-300
-
-    &:hover
-      background-color: var(--color-dark-background-hover)
-
-// Main content
-.main
+// Основной контент
+.main-content
   flex: 1
+  padding: var(--spacing-xl)
+  min-height: calc(100vh - 80px)
 
-// Page transitions
-.page-slide
-  &-enter-active,
-  &-leave-active
-    transition: all 0.3s ease-in-out
-
-  &-enter-from
-    opacity: 0
-    transform: translateX(1rem)
-
-  &-leave-to
-    opacity: 0
-    transform: translateX(-1rem)
+// Анимации страниц
+.page-slide-enter-active,
+.page-slide-leave-active
+  transition: var(--transition-normal)
 
-// Footer
-.footer
-  background-color: $gray-800
-  color: $white
-  padding: 2rem 0
+.page-slide-enter-from
+  opacity: 0
+  transform: translateX(30px)
 
-  .dark &
-    background-color: $gray-900
+.page-slide-leave-to
+  opacity: 0
+  transform: translateX(-30px)
 
-.footer__content
-  max-width: 1200px
-  margin: 0 auto
-  padding: 0 1rem
+// Утилитарные классы
+.text-center
+  text-align: center
 
-.footer__sections
-  display: grid
-  grid-template-columns: 1fr
-  gap: 2rem
+.text-left
+  text-align: left
 
-  @media (min-width: 768px)
-    grid-template-columns: repeat(3, 1fr)
+.text-right
+  text-align: right
 
-.footer__section
+.d-flex
   display: flex
-  flex-direction: column
 
-.footer__section-title
-  font-size: 1.125rem
-  font-weight: bold
-  margin-bottom: 1rem
-
-.footer__section-text
-  color: $gray-400
-  margin-bottom: 0.5rem
-
-.footer__links
-  display: flex
+.flex-column
   flex-direction: column
-  gap: 0.5rem
-
-.footer__link
-  color: $gray-400
-  text-decoration: none
-  transition: color 0.2s ease-in-out
-
-  &:hover
-    color: $white
-
-// Утилитарные классы с использованием CSS-переменных
-.btn-primary
-  background-color: var(--color-primary-600)
-  color: $white
-  padding: 0.5rem 1rem
-  border-radius: 0.5rem
-  font-weight: 500
-  transition: background-color 0.2s ease-in-out
-  border: none
-  cursor: pointer
-  text-decoration: none
-  display: inline-block
-  text-align: center
-
-  &:hover
-    background-color: var(--color-primary-700)
-
-.btn-secondary
-  background-color: var(--color-gray-200)
-  color: var(--color-gray-700)
-  padding: 0.5rem 1rem
-  border-radius: 0.5rem
-  font-weight: 500
-  transition: background-color 0.2s ease-in-out
-  border: none
-  cursor: pointer
-  text-decoration: none
-  display: inline-block
-  text-align: center
 
-  &:hover
-    background-color: var(--color-gray-300)
-
-  .dark &
-    background-color: var(--color-gray-700)
-    color: var(--color-gray-300)
-
-    &:hover
-      background-color: var(--color-gray-600)
+.align-items-center
+  align-items: center
 
-.card
-  background-color: $white
-  border-radius: 0.5rem
-  box-shadow: 0 1px 3px 0 var(--color-shadow-light)
-  padding: 1.5rem
+.justify-content-center
+  justify-content: center
 
-  .dark &
-    background-color: $gray-800
+.justify-content-between
+  justify-content: space-between
 
-.form-input
+.w-100
   width: 100%
-  padding: 0.5rem 0.75rem
-  border: 1px solid var(--color-border-light)
-  border-radius: 0.5rem
-  background-color: $white
-  color: $gray-900
-  outline: none
-  transition: all 0.2s ease-in-out
-
-  &:focus
-    outline: none
-    border-color: $primary-500
-    box-shadow: 0 0 0 2px var(--color-primary-500-a20)
-
-  .dark &
-    background-color: $gray-700
-    color: $white
-    border-color: var(--color-dark-border-light)
-
-    &:focus
-      border-color: $primary-500
-
-.form-label
-  display: block
-  font-size: 0.875rem
-  font-weight: 500
-  color: $gray-700
-  margin-bottom: 0.5rem
-
-  .dark &
-    color: $gray-300
-
-// Специальные классы для работы с прозрачностью
-.overlay
-  background-color: var(--color-background-overlay)
-
-.modal-backdrop
-  background-color: var(--color-background-modal)
-
-.tooltip
-  background-color: var(--color-background-tooltip)
-  color: $white
-  padding: 0.5rem 0.75rem
-  border-radius: 0.375rem
-  font-size: 0.875rem
-
-.hover-effect
-  transition: background-color 0.2s ease-in-out
-
-  &:hover
-    background-color: var(--color-background-hover)
-
-.active-state
-  background-color: var(--color-background-active)
-
-.border-transparent
-  border-color: var(--color-border-light)
-
-.text-muted
-  color: var(--color-text-secondary)
-
-// Темная тема
-@media (prefers-color-scheme: dark)
-  :root
-    color-scheme: dark
-
-// Утилиты для отладки
-.debug-border
-  border: 1px solid var(--color-primary-500-a50)
 
-.debug-bg
-  background-color: var(--color-accent-500-a20)
+.h-100
+  height: 100%
+
+.mt-1 { margin-top: var(--spacing-xs) }
+.mt-2 { margin-top: var(--spacing-sm) }
+.mt-3 { margin-top: var(--spacing-md) }
+.mt-4 { margin-top: var(--spacing-lg) }
+.mt-5 { margin-top: var(--spacing-xl) }
+
+.mb-1 { margin-bottom: var(--spacing-xs) }
+.mb-2 { margin-bottom: var(--spacing-sm) }
+.mb-3 { margin-bottom: var(--spacing-md) }
+.mb-4 { margin-bottom: var(--spacing-lg) }
+.mb-5 { margin-bottom: var(--spacing-xl) }
+
+.p-1 { padding: var(--spacing-xs) }
+.p-2 { padding: var(--spacing-sm) }
+.p-3 { padding: var(--spacing-md) }
+.p-4 { padding: var(--spacing-lg) }
+.p-5 { padding: var(--spacing-xl) }
+
+// Адаптивность
+@media (max-width: 768px)
+  .header
+    padding: var(--spacing-md)
+    flex-direction: column
+    gap: var(--spacing-md)
+  
+  .header-nav
+    flex-direction: column
+    gap: var(--spacing-md)
+  
+  .main-content
+    padding: var(--spacing-md)
+
+@media (max-width: 480px)
+  .header-nav-block
+    flex-direction: column
+    gap: var(--spacing-sm)
+  
+  .header-nav--menu
+    flex-wrap: wrap
+    justify-content: center