index.pug 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. div(class="admin")
  2. // Мобильное меню - кнопка бургер
  3. div(class="admin__mobile-toggle" @click="mobileMenuOpen = !mobileMenuOpen")
  4. div(class="admin__burger" :class="{'admin__burger--active': mobileMenuOpen}")
  5. span
  6. span
  7. span
  8. // Боковое меню для десктопа и мобильных устройств
  9. div(
  10. class="admin__sidebar"
  11. :class="{'admin__sidebar--mobile-open': mobileMenuOpen, 'admin__sidebar--collapsed': sidebarCollapsed}"
  12. )
  13. div(class="admin__sidebar-header")
  14. div(class="admin__brand" v-if="!sidebarCollapsed")
  15. img(
  16. v-if="currentDomainSettings && currentDomainSettings.logo"
  17. :src="currentDomainSettings.logo"
  18. :alt="currentDomainSettings.companyName || 'Браер-Колор'"
  19. class="admin__logo"
  20. )
  21. span(class="admin__company-name") {{ currentDomainSettings?.companyName || 'Браер-Колор' }}
  22. div(class="admin__sidebar-toggle" @click="sidebarCollapsed = !sidebarCollapsed")
  23. div(class="admin__toggle-icon" :class="{'admin__toggle-icon--collapsed': sidebarCollapsed}")
  24. svg(fill="none" stroke="currentColor" viewBox="0 0 24 24")
  25. path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 19l-7-7 7-7m8 14l-7-7 7-7")
  26. nav(class="admin__nav")
  27. div(class="admin__nav-section")
  28. h3(
  29. v-if="!sidebarCollapsed"
  30. class="admin__nav-section-title"
  31. ) Основные
  32. ul(class="admin__nav-list")
  33. li(
  34. v-for="item in mainMenuItems"
  35. :key="item.id"
  36. class="admin__nav-item"
  37. )
  38. a(
  39. :href="item.path"
  40. @click.prevent="navigateTo(item.path)"
  41. :class="getMenuItemClass(item)"
  42. class="admin__nav-link"
  43. )
  44. component(:is="item.icon" class="admin__nav-icon")
  45. span(
  46. v-if="!sidebarCollapsed"
  47. class="admin__nav-text"
  48. ) {{ item.name }}
  49. span(
  50. v-if="!sidebarCollapsed && item.badge"
  51. class="admin__nav-badge"
  52. ) {{ item.badge }}
  53. div(class="admin__nav-section")
  54. h3(
  55. v-if="!sidebarCollapsed"
  56. class="admin__nav-section-title"
  57. ) Контент
  58. ul(class="admin__nav-list")
  59. li(
  60. v-for="item in contentMenuItems"
  61. :key="item.id"
  62. class="admin__nav-item"
  63. )
  64. a(
  65. :href="item.path"
  66. @click.prevent="navigateTo(item.path)"
  67. :class="getMenuItemClass(item)"
  68. class="admin__nav-link"
  69. )
  70. component(:is="item.icon" class="admin__nav-icon")
  71. span(
  72. v-if="!sidebarCollapsed"
  73. class="admin__nav-text"
  74. ) {{ item.name }}
  75. div(class="admin__nav-section")
  76. h3(
  77. v-if="!sidebarCollapsed"
  78. class="admin__nav-section-title"
  79. ) Система
  80. ul(class="admin__nav-list")
  81. li(
  82. v-for="item in systemMenuItems"
  83. :key="item.id"
  84. class="admin__nav-item"
  85. )
  86. a(
  87. :href="item.path"
  88. @click.prevent="navigateTo(item.path)"
  89. :class="getMenuItemClass(item)"
  90. class="admin__nav-link"
  91. )
  92. component(:is="item.icon" class="admin__nav-icon")
  93. span(
  94. v-if="!sidebarCollapsed"
  95. class="admin__nav-text"
  96. ) {{ item.name }}
  97. div(class="admin__sidebar-footer" v-if="!sidebarCollapsed")
  98. div(class="admin__user-info")
  99. div(class="admin__user-avatar") {{ userInitials }}
  100. div(class="admin__user-details")
  101. span(class="admin__user-name") {{ user?.name || 'Администратор' }}
  102. span(class="admin__user-role") {{ user?.role || 'Admin' }}
  103. button(
  104. @click="logout"
  105. class="admin__logout-btn"
  106. )
  107. svg(fill="none" stroke="currentColor" viewBox="0 0 24 24")
  108. path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1")
  109. span Выйти
  110. // Основной контент
  111. div(
  112. class="admin__main"
  113. :class="{'admin__main--expanded': sidebarCollapsed, 'admin__main--mobile-open': mobileMenuOpen}"
  114. )
  115. div(class="admin__topbar")
  116. div(class="admin__breadcrumbs")
  117. span(
  118. v-for="(breadcrumb, index) in breadcrumbs"
  119. :key="index"
  120. class="admin__breadcrumb"
  121. )
  122. a(
  123. v-if="breadcrumb.path && index !== breadcrumbs.length - 1"
  124. :href="breadcrumb.path"
  125. @click.prevent="navigateTo(breadcrumb.path)"
  126. class="admin__breadcrumb-link"
  127. ) {{ breadcrumb.title }}
  128. span(v-else class="admin__breadcrumb-current") {{ breadcrumb.title }}
  129. span(
  130. v-if="index !== breadcrumbs.length - 1"
  131. class="admin__breadcrumb-separator"
  132. ) /
  133. div(class="admin__actions")
  134. button(
  135. @click="toggleTheme"
  136. class="admin__action-btn"
  137. :title="theme === 'light' ? 'Темная тема' : 'Светлая тема'"
  138. )
  139. svg(v-if="theme === 'light'" fill="none" stroke="currentColor" viewBox="0 0 24 24")
  140. path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z")
  141. svg(v-else fill="none" stroke="currentColor" viewBox="0 0 24 24")
  142. path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z")
  143. button(
  144. @click="refreshData"
  145. class="admin__action-btn"
  146. title="Обновить данные"
  147. )
  148. svg(fill="none" stroke="currentColor" viewBox="0 0 24 24")
  149. path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15")
  150. div(class="admin__notifications")
  151. button(
  152. @click="notificationsOpen = !notificationsOpen"
  153. class="admin__action-btn admin__notifications-btn"
  154. :class="{'admin__notifications-btn--active': notificationsOpen}"
  155. )
  156. svg(fill="none" stroke="currentColor" viewBox="0 0 24 24")
  157. path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-5 5v-5zM4.5 6.5h15M4.5 12h15")
  158. span(v-if="unreadNotifications > 0" class="admin__notification-badge") {{ unreadNotifications }}
  159. div(
  160. v-if="notificationsOpen"
  161. class="admin__notifications-dropdown"
  162. )
  163. div(class="admin__notifications-header")
  164. h4 Уведомления
  165. span(class="admin__notifications-count") {{ unreadNotifications }} новых
  166. div(class="admin__notifications-list")
  167. div(
  168. v-for="notification in notifications"
  169. :key="notification.id"
  170. class="admin__notification-item"
  171. :class="{'admin__notification-item--unread': !notification.read}"
  172. )
  173. div(class="admin__notification-icon")
  174. component(:is="notification.icon")
  175. div(class="admin__notification-content")
  176. p(class="admin__notification-title") {{ notification.title }}
  177. span(class="admin__notification-time") {{ notification.time }}
  178. button(
  179. @click="markAsRead(notification.id)"
  180. class="admin__notification-action"
  181. ) ×
  182. div(class="admin__content")
  183. router-view
  184. // Оверлей для мобильного меню
  185. div(
  186. v-if="mobileMenuOpen"
  187. class="admin__overlay"
  188. @click="mobileMenuOpen = false"
  189. )