temp.coffee 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. # обязательно подключение глобальных массивов
  2. globalThis.renderFns = require 'pug.json'
  3. globalThis.stylFns = require 'styl.json'
  4. # подключение мета информации (строго в данном фиде)
  5. document.head.insertAdjacentHTML 'beforeend','<meta charset="UTF-8">'
  6. document.head.insertAdjacentHTML 'beforeend','<meta name="viewport" content="width=device-width, initial-scale=1.0">'
  7. document.head.insertAdjacentHTML('beforeend','<title>Кохи Борбад - Концертный зал Душанбе</title>')
  8. # Настройка tailwind
  9. tailwind.config = require 'tailwind.config.js'
  10. # подключение основных стилей
  11. ## tailwind
  12. document.head.insertAdjacentHTML('beforeend','<style type="text/tailwindcss" page="main">'+stylFns['main.css']+'</style>')
  13. ## базовой стиль приложения
  14. document.head.insertAdjacentHTML('beforeend','<style type="text/tailwindcss" page="root">'+stylFns['app/temp.styl']+'</style>')
  15. # CouchDB сервис
  16. class CouchDBService
  17. constructor: ->
  18. @baseUrl = 'https://couchdb.favt.ru.net'
  19. @dbName = 'kohi_borbad_events'
  20. @headers =
  21. 'Content-Type': 'application/json'
  22. 'Authorization': 'Basic ' + btoa('oleg:631074')
  23. getAllEvents: ->
  24. try
  25. response = await fetch("#{@baseUrl}/#{@dbName}/_all_docs?include_docs=true", {
  26. method: 'GET'
  27. headers: @headers
  28. })
  29. if response.ok
  30. data = await response.json()
  31. events = data.rows.map (row) -> row.doc
  32. return events.filter (event) -> !event._id.startsWith('_design/')
  33. else
  34. debug.log "Ошибка получения мероприятий: "+response.statusText
  35. return []
  36. catch error
  37. debug.log "Ошибка подключения к CouchDB: "+error
  38. return []
  39. getFeaturedEvents: ->
  40. events = await @getAllEvents()
  41. events
  42. .filter (event) -> event.isFeatured || false
  43. .slice(0, 6)
  44. getSliderEvents: ->
  45. events = await @getAllEvents()
  46. events
  47. .filter (event) -> event.inSlider || false
  48. .map (event) ->
  49. id: event._id
  50. image: event.image || '/images/default-event.jpg'
  51. title: event.title
  52. description: event.shortDescription || event.description
  53. cta: event.cta || 'Подробнее'
  54. category: event.category
  55. # Маршруты
  56. routes = [
  57. { path: '/', component: require 'app/pages/Home' }
  58. { path: '/events', component: require 'app/pages/Events' }
  59. { path: '/about', component: require 'app/pages/About' }
  60. { path: '/contacts', component: require 'app/pages/Contacts' }
  61. ]
  62. # Глобальное определение vuejs приложения
  63. app = Vue.createApp
  64. name: 'app'
  65. data: ()->
  66. return
  67. theme: 'light'
  68. appState:
  69. events: []
  70. featuredEvents: []
  71. sliderEvents: []
  72. loading: true
  73. error: null
  74. modalState:
  75. currentModal: null
  76. modalProps: {}
  77. couchDBService: new CouchDBService()
  78. beforeMount: ()->
  79. debug.log "start beforeMount"
  80. # определение контекста vuejs приложения как глобальной переменной _
  81. globalThis._ = @
  82. render: (new Function '_ctx', '_cache', renderFns['app/temp.pug'])()
  83. mounted: ->
  84. # Предзагрузка темы
  85. if localStorage.theme == 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)
  86. @theme = 'dark'
  87. document.documentElement.classList.add('dark')
  88. else
  89. @theme = 'light'
  90. document.documentElement.classList.remove('dark')
  91. # Загрузка данных из CouchDB
  92. await @loadEventsData()
  93. # Обработчик открытия модальных окон
  94. EventBus.$on 'open-modal', (config) =>
  95. @modalState.currentModal = config.component
  96. @modalState.modalProps = config.props || {}
  97. methods:
  98. toggleTheme: ->
  99. @theme = if @theme == 'light' then 'dark' else 'light'
  100. localStorage.setItem 'theme', @theme
  101. document.documentElement.classList.toggle 'dark'
  102. @$emit 'theme-changed', @theme
  103. loadEventsData: ->
  104. @appState.loading = true
  105. try
  106. [events, featuredEvents, sliderEvents] = await Promise.all([
  107. @couchDBService.getAllEvents()
  108. @couchDBService.getFeaturedEvents()
  109. @couchDBService.getSliderEvents()
  110. ])
  111. @appState.events = events
  112. @appState.featuredEvents = featuredEvents
  113. @appState.sliderEvents = sliderEvents
  114. @appState.error = null
  115. catch error
  116. debug.log "Ошибка загрузки данных: "+error
  117. @appState.error = 'Не удалось загрузить данные мероприятий'
  118. @loadTestData()
  119. finally
  120. @appState.loading = false
  121. loadTestData: ->
  122. # Тестовые данные на случай недоступности CouchDB
  123. @appState.events = [
  124. {
  125. _id: '1'
  126. title: 'Концерт симфонического оркестра'
  127. date: '2025-10-15'
  128. time: '19:00'
  129. description: 'Произведения Чайковского и Рахманинова в исполнении Национального симфонического оркестра'
  130. image: '/images/event-classical.jpg'
  131. category: 'classical'
  132. price: 50
  133. venue: 'Большой зал'
  134. duration: '2 часа 30 минут'
  135. ageRestriction: '12+'
  136. availableTickets: 45
  137. isFeatured: true
  138. inSlider: true
  139. shortDescription: 'Шедевры классической музыки'
  140. cta: 'Купить билеты'
  141. }
  142. {
  143. _id: '2'
  144. title: 'Вечер таджикской народной музыки'
  145. date: '2025-10-20'
  146. time: '18:30'
  147. description: 'Выступление фольклорного ансамбля "Шашмаком" с программой традиционных мелодий и танцев'
  148. image: '/images/event-folk.jpg'
  149. category: 'folk'
  150. price: 30
  151. venue: 'Малый зал'
  152. duration: '2 часа'
  153. ageRestriction: '6+'
  154. availableTickets: 28
  155. isFeatured: true
  156. inSlider: true
  157. shortDescription: 'Традиционные мелодии и танцы Таджикистана'
  158. cta: 'Узнать больше'
  159. }
  160. {
  161. _id: '3'
  162. title: 'Джазовый фестиваль "Borbad Jazz"'
  163. date: '2025-10-25'
  164. time: '20:00'
  165. description: 'Международные джазовые коллективы из Европы и Азии в уникальной акустике зала'
  166. image: '/images/event-jazz.jpg'
  167. category: 'jazz'
  168. price: 70
  169. venue: 'Большой зал'
  170. duration: '3 часа'
  171. ageRestriction: '16+'
  172. availableTickets: 15
  173. isFeatured: true
  174. inSlider: true
  175. shortDescription: 'Международные джазовые коллективы'
  176. cta: 'Смотреть расписание'
  177. }
  178. ]
  179. @appState.featuredEvents = @appState.events.filter((event) -> event.isFeatured).slice(0, 6)
  180. @appState.sliderEvents = @appState.events.filter((event) -> event.inSlider).map (event) ->
  181. id: event._id
  182. image: event.image
  183. title: event.title
  184. description: event.shortDescription
  185. cta: event.cta
  186. category: event.category
  187. getEvents: -> @appState.events
  188. getFeaturedEvents: -> @appState.featuredEvents
  189. getSliderEvents: -> @appState.sliderEvents
  190. isLoading: -> @appState.loading
  191. hasError: -> @appState.error
  192. closeModal: ->
  193. @modalState.currentModal = null
  194. @modalState.modalProps = {}
  195. components:
  196. 'themetoggle': require 'app/shared/ThemeToggle'
  197. 'multilevelmenu': require 'app/shared/MultiLevelMenu'
  198. 'imageslider': require 'app/shared/ImageSlider'
  199. 'modalwindow': require 'app/shared/ModalWindow'
  200. 'formvalidator': require 'app/shared/FormValidator'
  201. 'filtersort': require 'app/shared/FilterSort'
  202. 'eventdetailmodal': require 'app/shared/EventDetailModal'
  203. 'successmodal': require 'app/shared/SuccessModal'
  204. # Создаем глобальную шину событий
  205. globalThis.EventBus = new Vue()
  206. app.use(VueRouter.createRouter({
  207. routes: routes
  208. history: VueRouter.createWebHistory()
  209. scrollBehavior: (to, from, savedPosition) ->
  210. if savedPosition
  211. return savedPosition
  212. else
  213. return { x: 0, y: 0 }
  214. }))
  215. # Глобальные функции для работы с модальными окнами
  216. globalThis.openModal = (component, props = {}) ->
  217. EventBus.$emit 'open-modal', { component, props }
  218. globalThis.closeModal = ->
  219. EventBus.$emit 'close-modal'
  220. # подключаем в body ОБЯЗАТЕЛЬНО!!!
  221. app.mount('body')
  222. debug.log "Vue application initialized successfully"