# обязательно подключение глобальных массивов
globalThis.renderFns = require 'pug.json'
globalThis.stylFns = require 'styl.json'
# подключение мета информации (строго в данном фиде)
document.head.insertAdjacentHTML 'beforeend',''
document.head.insertAdjacentHTML 'beforeend',''
document.head.insertAdjacentHTML('beforeend','
Кохи Борбад - Концертный зал Душанбе')
# Настройка tailwind
tailwind.config = require 'tailwind.config.js'
# подключение основных стилей
## tailwind
document.head.insertAdjacentHTML('beforeend','')
## базовой стиль приложения
document.head.insertAdjacentHTML('beforeend','')
# CouchDB сервис
class CouchDBService
constructor: ->
@baseUrl = 'https://couchdb.favt.ru.net'
@dbName = 'kohi_borbad_events'
@headers =
'Content-Type': 'application/json'
'Authorization': 'Basic ' + btoa('oleg:631074')
getAllEvents: ->
try
response = await fetch("#{@baseUrl}/#{@dbName}/_all_docs?include_docs=true", {
method: 'GET'
headers: @headers
})
if response.ok
data = await response.json()
events = data.rows.map (row) -> row.doc
return events.filter (event) -> !event._id.startsWith('_design/')
else
debug.log "Ошибка получения мероприятий: "+response.statusText
return []
catch error
debug.log "Ошибка подключения к CouchDB: "+error
return []
getFeaturedEvents: ->
events = await @getAllEvents()
events
.filter (event) -> event.isFeatured || false
.slice(0, 6)
getSliderEvents: ->
events = await @getAllEvents()
events
.filter (event) -> event.inSlider || false
.map (event) ->
id: event._id
image: event.image || '/images/default-event.jpg'
title: event.title
description: event.shortDescription || event.description
cta: event.cta || 'Подробнее'
category: event.category
# Маршруты
routes = [
{ path: '/', component: require 'app/pages/Home' }
{ path: '/events', component: require 'app/pages/Events' }
{ path: '/about', component: require 'app/pages/About' }
{ path: '/contacts', component: require 'app/pages/Contacts' }
]
# Глобальное определение vuejs приложения
app = Vue.createApp
name: 'app'
data: ()->
return
theme: 'light'
appState:
events: []
featuredEvents: []
sliderEvents: []
loading: true
error: null
modalState:
currentModal: null
modalProps: {}
couchDBService: new CouchDBService()
beforeMount: ()->
debug.log "start beforeMount"
# определение контекста vuejs приложения как глобальной переменной _
globalThis._ = @
render: (new Function '_ctx', '_cache', renderFns['app/temp.pug'])()
mounted: ->
# Предзагрузка темы
if localStorage.theme == 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)
@theme = 'dark'
document.documentElement.classList.add('dark')
else
@theme = 'light'
document.documentElement.classList.remove('dark')
# Загрузка данных из CouchDB
await @loadEventsData()
# Обработчик открытия модальных окон
EventBus.$on 'open-modal', (config) =>
@modalState.currentModal = config.component
@modalState.modalProps = config.props || {}
methods:
toggleTheme: ->
@theme = if @theme == 'light' then 'dark' else 'light'
localStorage.setItem 'theme', @theme
document.documentElement.classList.toggle 'dark'
@$emit 'theme-changed', @theme
loadEventsData: ->
@appState.loading = true
try
[events, featuredEvents, sliderEvents] = await Promise.all([
@couchDBService.getAllEvents()
@couchDBService.getFeaturedEvents()
@couchDBService.getSliderEvents()
])
@appState.events = events
@appState.featuredEvents = featuredEvents
@appState.sliderEvents = sliderEvents
@appState.error = null
catch error
debug.log "Ошибка загрузки данных: "+error
@appState.error = 'Не удалось загрузить данные мероприятий'
@loadTestData()
finally
@appState.loading = false
loadTestData: ->
# Тестовые данные на случай недоступности CouchDB
@appState.events = [
{
_id: '1'
title: 'Концерт симфонического оркестра'
date: '2025-10-15'
time: '19:00'
description: 'Произведения Чайковского и Рахманинова в исполнении Национального симфонического оркестра'
image: '/images/event-classical.jpg'
category: 'classical'
price: 50
venue: 'Большой зал'
duration: '2 часа 30 минут'
ageRestriction: '12+'
availableTickets: 45
isFeatured: true
inSlider: true
shortDescription: 'Шедевры классической музыки'
cta: 'Купить билеты'
}
{
_id: '2'
title: 'Вечер таджикской народной музыки'
date: '2025-10-20'
time: '18:30'
description: 'Выступление фольклорного ансамбля "Шашмаком" с программой традиционных мелодий и танцев'
image: '/images/event-folk.jpg'
category: 'folk'
price: 30
venue: 'Малый зал'
duration: '2 часа'
ageRestriction: '6+'
availableTickets: 28
isFeatured: true
inSlider: true
shortDescription: 'Традиционные мелодии и танцы Таджикистана'
cta: 'Узнать больше'
}
{
_id: '3'
title: 'Джазовый фестиваль "Borbad Jazz"'
date: '2025-10-25'
time: '20:00'
description: 'Международные джазовые коллективы из Европы и Азии в уникальной акустике зала'
image: '/images/event-jazz.jpg'
category: 'jazz'
price: 70
venue: 'Большой зал'
duration: '3 часа'
ageRestriction: '16+'
availableTickets: 15
isFeatured: true
inSlider: true
shortDescription: 'Международные джазовые коллективы'
cta: 'Смотреть расписание'
}
]
@appState.featuredEvents = @appState.events.filter((event) -> event.isFeatured).slice(0, 6)
@appState.sliderEvents = @appState.events.filter((event) -> event.inSlider).map (event) ->
id: event._id
image: event.image
title: event.title
description: event.shortDescription
cta: event.cta
category: event.category
getEvents: -> @appState.events
getFeaturedEvents: -> @appState.featuredEvents
getSliderEvents: -> @appState.sliderEvents
isLoading: -> @appState.loading
hasError: -> @appState.error
closeModal: ->
@modalState.currentModal = null
@modalState.modalProps = {}
components:
'themetoggle': require 'app/shared/ThemeToggle'
'multilevelmenu': require 'app/shared/MultiLevelMenu'
'imageslider': require 'app/shared/ImageSlider'
'modalwindow': require 'app/shared/ModalWindow'
'formvalidator': require 'app/shared/FormValidator'
'filtersort': require 'app/shared/FilterSort'
'eventdetailmodal': require 'app/shared/EventDetailModal'
'successmodal': require 'app/shared/SuccessModal'
# Создаем глобальную шину событий
globalThis.EventBus = new Vue()
app.use(VueRouter.createRouter({
routes: routes
history: VueRouter.createWebHistory()
scrollBehavior: (to, from, savedPosition) ->
if savedPosition
return savedPosition
else
return { x: 0, y: 0 }
}))
# Глобальные функции для работы с модальными окнами
globalThis.openModal = (component, props = {}) ->
EventBus.$emit 'open-modal', { component, props }
globalThis.closeModal = ->
EventBus.$emit 'close-modal'
# подключаем в body ОБЯЗАТЕЛЬНО!!!
app.mount('body')
debug.log "Vue application initialized successfully"