Gogs há 3 semanas atrás
pai
commit
d100bd6170

BIN
assets/000.jpg


BIN
assets/000.png


BIN
assets/001.jpg


BIN
assets/002.jpg


BIN
assets/003.jpg


+ 270 - 0
scripts/seed-events.coffee

@@ -0,0 +1,270 @@
+#!/usr/bin/env coffee
+
+# Скрипт для добавления тестовых мероприятий в CouchDB
+
+class EventSeeder
+  constructor: ->
+    @baseUrl = 'http://localhost:5984'
+    @dbName = 'kohi_borbad_events'
+    @headers = 
+      'Content-Type': 'application/json'
+      'Authorization': 'Basic ' + Buffer.from('oleg:631074').toString('base64')
+    
+    # Тестовые мероприятия
+    @testEvents = [
+      {
+        _id: 'event_classical_001'
+        title: 'Концерт симфонического оркестра'
+        date: '2025-10-15'
+        time: '19:00'
+        description: 'Произведения Чайковского и Рахманинова в исполнении Национального симфонического оркестра под руководством маэстро Фирдавса Абдурахмонова. Незабываемый вечер классической музыки в акустике мирового уровня.'
+        shortDescription: 'Шедевры классической музыки в исполнении Национального симфонического оркестра'
+        image: '/images/event-classical.jpg'
+        category: 'classical'
+        price: 50
+        venue: 'Большой зал'
+        duration: '2 часа 30 минут'
+        ageRestriction: '12+'
+        availableTickets: 45
+        isFeatured: true
+        inSlider: true
+        cta: 'Купить билеты'
+        createdAt: new Date().toISOString()
+        updatedAt: new Date().toISOString()
+      }
+      {
+        _id: 'event_folk_001'
+        title: 'Вечер таджикской народной музыки'
+        date: '2025-10-20'
+        time: '18:30'
+        description: 'Выступление фольклорного ансамбля "Шашмаком" с программой традиционных мелодий и танцев. Погрузитесь в богатую культурную традицию Таджикистана через музыку, песни и танцы.'
+        shortDescription: 'Традиционные мелодии и танцы Таджикистана'
+        image: '/images/event-folk.jpg'
+        category: 'folk'
+        price: 30
+        venue: 'Малый зал'
+        duration: '2 часа'
+        ageRestriction: '6+'
+        availableTickets: 28
+        isFeatured: true
+        inSlider: true
+        cta: 'Узнать больше'
+        createdAt: new Date().toISOString()
+        updatedAt: new Date().toISOString()
+      }
+      {
+        _id: 'event_jazz_001'
+        title: 'Джазовый фестиваль "Borbad Jazz"'
+        date: '2025-10-25'
+        time: '20:00'
+        description: 'Международные джазовые коллективы из Европы и Азии в уникальной акустике зала. Три дня незабываемой музыки от лучших джазменов мира. От традиционного джаза до современных экспериментов.'
+        shortDescription: 'Международные джазовые коллективы'
+        image: '/images/event-jazz.jpg'
+        category: 'jazz'
+        price: 70
+        venue: 'Большой зал'
+        duration: '3 часа'
+        ageRestriction: '16+'
+        availableTickets: 15
+        isFeatured: true
+        inSlider: true
+        cta: 'Смотреть расписание'
+        createdAt: new Date().toISOString()
+        updatedAt: new Date().toISOString()
+      }
+      {
+        _id: 'event_pop_001'
+        title: 'Концерт популярной музыки'
+        date: '2025-10-28'
+        time: '19:30'
+        description: 'Лучшие поп-исполнители Таджикистана представят новые хиты и классические композиции. Энергичное шоу с современной хореографией и световыми эффектами.'
+        shortDescription: 'Лучшие поп-исполнители страны'
+        image: '/images/event-pop.jpg'
+        category: 'pop'
+        price: 45
+        venue: 'Большой зал'
+        duration: '2 часа 15 минут'
+        ageRestriction: '12+'
+        availableTickets: 67
+        isFeatured: true
+        inSlider: false
+        cta: 'Купить билеты'
+        createdAt: new Date().toISOString()
+        updatedAt: new Date().toISOString()
+      }
+      {
+        _id: 'event_opera_001'
+        title: 'Оперный гала-концерт'
+        date: '2025-11-02'
+        time: '18:00'
+        description: 'Известные оперные певцы исполнят арии из мировых шедевров оперного искусства. Вечер великой музыки в исполнении мастеров оперной сцены.'
+        shortDescription: 'Арии из мировых оперных шедевров'
+        image: '/images/event-opera.jpg'
+        category: 'classical'
+        price: 80
+        venue: 'Большой зал'
+        duration: '2 часа 45 минут'
+        ageRestriction: '12+'
+        availableTickets: 23
+        isFeatured: false
+        inSlider: false
+        cta: 'Забронировать места'
+        createdAt: new Date().toISOString()
+        updatedAt: new Date().toISOString()
+      }
+      {
+        _id: 'event_dance_001'
+        title: 'Танцевальное шоу "Восточные ритмы"'
+        date: '2025-11-05'
+        time: '19:00'
+        description: 'Традиционные и современные танцевальные коллективы представят красочное шоу. Яркие костюмы, зажигательная музыка и мастерство танцовщиков со всего Таджикистана.'
+        shortDescription: 'Традиционные и современные танцы'
+        image: '/images/event-dance.jpg'
+        category: 'dance'
+        price: 35
+        venue: 'Большой зал'
+        duration: '2 часа 30 минут'
+        ageRestriction: '6+'
+        availableTickets: 89
+        isFeatured: true
+        inSlider: true
+        cta: 'Посмотреть программу'
+        createdAt: new Date().toISOString()
+        updatedAt: new Date().toISOString()
+      }
+      {
+        _id: 'event_chamber_001'
+        title: 'Камерная музыка: Струнный квартет'
+        date: '2025-11-08'
+        time: '17:00'
+        description: 'Изысканная программа камерной музыки в исполнении ведущего струнного квартета страны. Интимная атмосфера и тонкое звучание в акустике камерного зала.'
+        shortDescription: 'Изысканная камерная музыка'
+        image: '/images/event-chamber.jpg'
+        category: 'classical'
+        price: 40
+        venue: 'Камерный зал'
+        duration: '1 час 45 минут'
+        ageRestriction: '12+'
+        availableTickets: 34
+        isFeatured: false
+        inSlider: false
+        cta: 'Приобрести билеты'
+        createdAt: new Date().toISOString()
+        updatedAt: new Date().toISOString()
+      }
+      {
+        _id: 'event_experimental_001'
+        title: 'Фестиваль современной музыки'
+        date: '2025-11-12'
+        time: '20:30'
+        description: 'Экспериментальные проекты и инновационные музыкальные направления. Откройте для себя новые грани музыкального искусства от молодых композиторов и исполнителей.'
+        shortDescription: 'Экспериментальные музыкальные проекты'
+        image: '/images/event-modern.jpg'
+        category: 'experimental'
+        price: 55
+        venue: 'Малый зал'
+        duration: '3 часа'
+        ageRestriction: '18+'
+        availableTickets: 18
+        isFeatured: false
+        inSlider: true
+        cta: 'Исследовать программу'
+        createdAt: new Date().toISOString()
+        updatedAt: new Date().toISOString()
+      }
+    ]
+
+  # Проверить существование базы данных
+  checkDatabase: ->
+    try
+      response = await fetch("#{@baseUrl}/#{@dbName}", {
+        method: 'GET'
+        headers: @headers
+      })
+      
+      if response.ok
+        console.log '✅ База данных существует'
+        return true
+      else if response.status == 404
+        console.log '📁 База данных не существует, создаем...'
+        return await this.createDatabase()
+      else
+        console.error '❌ Ошибка проверки базы данных:', response.statusText
+        return false
+    catch error
+      console.error '❌ Ошибка подключения к CouchDB:', error.message
+      return false
+
+  # Создать базу данных
+  createDatabase: ->
+    try
+      response = await fetch("#{@baseUrl}/#{@dbName}", {
+        method: 'PUT'
+        headers: @headers
+      })
+      
+      if response.ok
+        console.log '✅ База данных создана успешно'
+        return true
+      else
+        console.error '❌ Ошибка создания базы данных:', response.statusText
+        return false
+    catch error
+      console.error '❌ Ошибка создания базы данных:', error.message
+      return false
+
+  # Добавить мероприятие
+  addEvent: (event) ->
+    try
+      response = await fetch("#{@baseUrl}/#{@dbName}/#{event._id}", {
+        method: 'PUT'
+        headers: @headers
+        body: JSON.stringify(event)
+      })
+      
+      if response.ok
+        result = await response.json()
+        console.log "✅ Мероприятие добавлено: #{event.title}"
+        return { success: true, id: result.id }
+      else
+        console.error "❌ Ошибка добавления мероприятия #{event.title}:", response.statusText
+        return { success: false, error: response.statusText }
+    catch error
+      console.error "❌ Ошибка добавления мероприятия #{event.title}:", error.message
+      return { success: false, error: error.message }
+
+  # Основная функция заполнения базы
+  seed: ->
+    console.log '🎭 Начало заполнения базы данных мероприятиями...'
+    
+    # Проверяем базу данных
+    databaseExists = await this.checkDatabase()
+    if not databaseExists
+      console.log '❌ Не удалось подключиться к базе данных'
+      process.exit(1)
+    
+    # Добавляем мероприятия
+    successCount = 0
+    for event in @testEvents
+      result = await this.addEvent(event)
+      if result.success
+        successCount += 1
+      # Небольшая задержка между запросами
+      await new Promise (resolve) -> setTimeout resolve, 100
+    
+    console.log "\n🎉 Заполнение завершено!"
+    console.log "✅ Успешно добавлено: #{successCount} из #{@testEvents.length} мероприятий"
+    
+    if successCount == @testEvents.length
+      console.log '🎊 Все мероприятия успешно добавлены в базу данных!'
+    else
+      console.log '⚠️  Некоторые мероприятия не были добавлены'
+
+# Запуск скрипта
+seeder = new EventSeeder()
+seeder.seed().then ->
+  console.log '\n✨ Скрипт завершил работу'
+  process.exit(0)
+.catch (error) ->
+  console.error '\n💥 Критическая ошибка:', error
+  process.exit(1)

+ 1 - 0
vue/app/shared/AppLink/AppLink

@@ -0,0 +1 @@
+./src/braer-color.s5l.ru/vue/app/comp/AppLink

+ 12 - 0
vue/app/shared/AppLink/index.coffee

@@ -0,0 +1,12 @@
+document.head.insertAdjacentHTML('beforeend','<style  type="text/tailwindcss" component="AppLink">'+stylFns['app/shared/AppLink/index.styl']+'</style>')
+module.exports =
+    default:
+        render: (new Function '_ctx', '_cache', renderFns['app/shared/AppLink/index.pug'])()
+        name: 'AppLink'
+        props:
+           to:
+               type: [String, Object]
+               required: true
+        computed:
+            isExternal: ()->
+                return @.to.startsWith('http')

+ 6 - 0
vue/app/shared/AppLink/index.pug

@@ -0,0 +1,6 @@
+//a(v-if="isExternal" v-bind="$attrs" :href="to" target="_blank" rel="noopener" )
+//    slot
+//router-link(v-else v-bind="$attrs" :to="to")
+//    slot
+span {{ isExternal }} -- {{ to }}
+    slot

+ 1 - 0
vue/app/shared/AppLink/index.styl

@@ -0,0 +1 @@
+

+ 20 - 0
vue/app/shared/SuccessModal/index.coffee

@@ -0,0 +1,20 @@
+# vue/app/shared/SuccessModal/index.coffee
+document.head.insertAdjacentHTML('beforeend','<style type="text/tailwindcss" component="SuccessModal">'+stylFns['app/shared/SuccessModal/index.styl']+'</style>')
+
+module.exports =
+    name: 'SuccessModal'
+    render: (new Function '_ctx', '_cache', renderFns['app/shared/SuccessModal/index.pug'])()
+    props:
+        isVisible:
+            type: Boolean
+            default: false
+        title:
+            type: String
+            default: 'Успешно!'
+        content:
+            type: String
+            required: true
+    mounted: ->
+        debug.log "SuccessModal component mounted"
+    methods: {}
+    emits: ['update:isVisible']

+ 27 - 0
vue/app/shared/SuccessModal/index.pug

@@ -0,0 +1,27 @@
+ModalWindow(
+    :isVisible="isVisible"
+    @update:isVisible="$emit('update:isVisible', $event)"
+    :title="title"
+    :showFooter="false"
+    :contentClass="'max-w-md'"
+)
+    template([body])
+        div(class="success-content text-center")
+            div(class="success-icon mb-4")
+                svg(
+                    class="w-16 h-16 mx-auto text-green-500"
+                    fill="none"
+                    stroke="currentColor"
+                    viewBox="0 0 24 24"
+                )
+                    path(
+                        stroke-linecap="round"
+                        stroke-linejoin="round"
+                        stroke-width="2"
+                        d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
+                    )
+            p(class="text-gray-600 dark:text-gray-400 mb-6 leading-relaxed") {{ content }}
+            button(
+                @click="$emit('update:isVisible', false)"
+                class="bg-accent text-white px-6 py-3 rounded-lg font-medium hover:bg-yellow-600 transition-colors w-full"
+            ) Понятно

+ 33 - 0
vue/app/shared/SuccessModal/index.styl

@@ -0,0 +1,33 @@
+// vue/app/shared/SuccessModal/index.styl
+// Стили исключительно для модального окна успеха
+
+.success-content
+    .success-icon
+        animation: successIconAppear 0.6s ease-out forwards
+        
+        svg
+            transition: all 0.3s ease
+            
+            &:hover
+                transform: scale(1.05)
+                filter: drop-shadow(0 4px 8px rgba(34, 197, 94, 0.3))
+
+// Анимация появления иконки
+@keyframes successIconAppear
+    0%
+        opacity: 0
+        transform: scale(0.5) rotate(-180deg)
+    60%
+        opacity: 1
+        transform: scale(1.1) rotate(10deg)
+    100%
+        opacity: 1
+        transform: scale(1) rotate(0deg)
+
+// Адаптивность для мобильных устройств
+@media (max-width: 640px)
+    .success-content
+        .success-icon
+            svg
+                width: 4rem
+                height: 4rem