Gogs 3 hete
szülő
commit
8c4ed3a1ad

+ 57 - 0
README.md

@@ -16,6 +16,63 @@
 Важно: мета данные добавляются через app/temp.coffe
 базовым тегоьм для vuejs является body, app/index.pug начинается с div,
 теги html, head, body ЗАПРЕЩЕНО использовать.
+### пример кода app/temp.coffee
+```
+# обязательно подключение глобальных массивов
+globalThis.renderFns = require 'pug.json'
+globalThis.stylFns   = require 'styl.json'
+
+# подключение мета информации (строго в данном фиде)
+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>')
+
+# Настройка tailwind
+tailwind.config = require 'tailwind.config.js'
+
+# подключение основных стилей
+## tailwind
+document.head.insertAdjacentHTML('beforeend','<style  type="text/tailwindcss"  page="main">'+stylFns['main.css']+'</style>')
+## базовой стиль приложения
+document.head.insertAdjacentHTML('beforeend','<style  type="text/tailwindcss"  page="root">'+stylFns['app/temp.styl']+'</style>')
+
+# Маршруты
+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  {}
+  beforeMount: ()->
+        debug.log "start beforeMount"
+        globalThis._ = @
+  render: (new Function '_ctx', '_cache', renderFns['app/temp.pug'])()
+  mounted: ->{}
+  methods: {}
+  components:
+      'themetoggle':    require 'app/shared/ThemeToggle'
+      'multilevelmenu': require 'app/shared/MultiLevelMenu'
+      'imageslider':    require 'app/shared/ImageSlider'
+app.use(VueRouter.createRouter({
+  routes: routes
+  history: VueRouter.createWebHistory()
+  scrollBehavior: (to, from, savedPosition) ->
+    if savedPosition
+      return savedPosition
+    else
+      return { x: 0, y: 0 }
+}))
+
+# подключаем в body ОБЯЗАТЕЛЬНО!!!
+app.mount('body')
+```
+
 
 ## Радота с кодом
 всегда приводи полный листинг файлов

+ 54 - 0
vue/app/pages/Contacts/index.coffee

@@ -0,0 +1,54 @@
+# vue/app/pages/Contacts/index.coffee
+document.head.insertAdjacentHTML('beforeend','<style type="text/tailwindcss">'+stylFns['app/pages/Contacts/index.styl']+'</style>')
+
+module.exports =
+    name: 'Contacts'
+    render: (new Function '_ctx', '_cache', renderFns['app/pages/Contacts/index.pug'])()
+    data: ->
+        contactInfo:
+            phone: '+992 372 27 09 46'
+            address: 'просп. Исмоила Сомони, 26'
+            director: 'Джумахон Розикзода'
+            deputyDirector: 'Азимов Махмадюсуф'
+        workingHours: [
+            { days: 'Понедельник - Пятница', hours: '9:00 - 18:00' }
+            { days: 'Суббота', hours: '10:00 - 16:00' }
+            { days: 'Воскресенье', hours: 'Выходной' }
+        ]
+        transportInfo:
+            buses: ['1', '2', '3', '4', '8', '12', '18']
+            minibuses: ['1', '2', '3', '4', '8', '12', '18', '27', '34']
+    mounted: ->
+        @setupAnimations()
+        debug.log "Contacts page mounted"
+    methods:
+        setupAnimations: ->
+            observer = new IntersectionObserver (entries) ->
+                entries.forEach (entry) ->
+                    if entry.isIntersecting
+                        entry.target.classList.add('animate-fade-in-up')
+            ,
+                threshold: 0.1
+            
+            document.querySelectorAll('.contacts-section .bg-white, .contacts-section .bg-gray-800').forEach (el) ->
+                observer.observe(el)
+
+        handleContactSubmit: (formData) ->
+            debug.log "Contact form submitted: " + JSON.stringify(formData)
+            
+            @$root.$emit('open-modal', 
+                component: 'SuccessModal'
+                props:
+                    title: 'Сообщение отправлено'
+                    content: 'Мы получили ваше сообщение и свяжемся с вами в ближайшее время.'
+            )
+
+        showOnMap: ->
+            debug.log "Showing location on map"
+            address = encodeURIComponent(@contactInfo.address + ', Душанбе, Таджикистан')
+            mapUrl = "https://yandex.ru/maps/?text=#{address}"
+            window.open(mapUrl, '_blank')
+
+        callPhone: ->
+            debug.log "Calling phone: " + @contactInfo.phone
+            window.location.href = "tel:#{@contactInfo.phone.replace(/\s/g, '')}"

+ 110 - 0
vue/app/pages/Contacts/index.pug

@@ -0,0 +1,110 @@
+section(class="min-h-screen bg-gray-50 dark:bg-gray-900 py-12 contacts-section")
+    div(class="container mx-auto px-4")
+        div(class="text-center mb-16")
+            h1(class="text-4xl md:text-5xl font-bold text-gray-800 dark:text-white mb-6") Контакты
+            div(class="w-24 h-1 bg-accent mx-auto")
+            p(class="text-xl text-gray-600 dark:text-gray-400 mt-6 max-w-3xl mx-auto") Свяжитесь с нами для получения информации о мероприятиях и сотрудничестве
+
+        div(class="grid grid-cols-1 lg:grid-cols-2 gap-12 items-start")
+            div(class="space-y-8")
+                div(class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-8 animate-fade-in-up animation-delay-100")
+                    div(class="flex items-center mb-6")
+                        div(class="w-12 h-12 bg-blue-100 dark:bg-blue-900 rounded-lg flex items-center justify-center mr-4")
+                            svg(class="w-6 h-6 text-blue-600 dark:text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24")
+                                path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z")
+                        h2(class="text-2xl font-bold text-gray-800 dark:text-white") Адрес
+                    div(class="space-y-4")
+                        div(class="flex items-start")
+                            svg(class="w-5 h-5 text-accent mt-1 mr-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24")
+                                path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z")
+                            div
+                                p(class="text-lg font-medium text-gray-800 dark:text-white") просп. Исмоила Сомони, 26
+                                p(class="text-gray-600 dark:text-gray-400") Душанбе, Таджикистан
+
+                div(class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-8 animate-fade-in-up animation-delay-200")
+                    div(class="flex items-center mb-6")
+                        div(class="w-12 h-12 bg-green-100 dark:bg-green-900 rounded-lg flex items-center justify-center mr-4")
+                            svg(class="w-6 h-6 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24")
+                                path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z")
+                        h2(class="text-2xl font-bold text-gray-800 dark:text-white") Телефоны
+                    div(class="space-y-4")
+                        div(class="flex items-center")
+                            svg(class="w-5 h-5 text-accent mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24")
+                                path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z")
+                            div
+                                p(class="text-lg font-medium text-gray-800 dark:text-white") +992 372 27 09 46
+                                p(class="text-gray-600 dark:text-gray-400") Основной телефон
+
+                div(class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-8 animate-fade-in-up animation-delay-300")
+                    div(class="flex items-center mb-6")
+                        div(class="w-12 h-12 bg-purple-100 dark:bg-purple-900 rounded-lg flex items-center justify-center mr-4")
+                            svg(class="w-6 h-6 text-purple-600 dark:text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24")
+                                path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z")
+                        h2(class="text-2xl font-bold text-gray-800 dark:text-white") Руководство
+                    div(class="space-y-6")
+                        div(class="border-l-4 border-accent pl-4")
+                            h3(class="text-lg font-bold text-gray-800 dark:text-white mb-1") Джумахон Розикзода
+                            p(class="text-accent font-medium") Директор
+                        div(class="border-l-4 border-green-500 pl-4")
+                            h3(class="text-lg font-bold text-gray-800 dark:text-white mb-1") Азимов Махмадюсуф
+                            p(class="text-green-500 font-medium") Заместитель директора
+
+            div(class="space-y-8")
+                div(class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-8 animate-fade-in-up animation-delay-200")
+                    div(class="flex items-center mb-6")
+                        div(class="w-12 h-12 bg-orange-100 dark:bg-orange-900 rounded-lg flex items-center justify-center mr-4")
+                            svg(class="w-6 h-6 text-orange-600 dark:text-orange-400" fill="none" stroke="currentColor" viewBox="0 0 24 24")
+                                path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z")
+                        h2(class="text-2xl font-bold text-gray-800 dark:text-white") Часы работы
+                    div(class="space-y-4")
+                        div(class="flex justify-between items-center py-2 border-b border-gray-200 dark:border-gray-700")
+                            span(class="text-gray-700 dark:text-gray-300") Понедельник - Пятница
+                            span(class="font-medium text-gray-800 dark:text-white") 9:00 - 18:00
+                        div(class="flex justify-between items-center py-2 border-b border-gray-200 dark:border-gray-700")
+                            span(class="text-gray-700 dark:text-gray-300") Суббота
+                            span(class="font-medium text-gray-800 dark:text-white") 10:00 - 16:00
+                        div(class="flex justify-between items-center py-2")
+                            span(class="text-gray-700 dark:text-gray-300") Воскресенье
+                            span(class="font-medium text-gray-800 dark:text-white") Выходной
+
+                div(class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-8 animate-fade-in-up animation-delay-300")
+                    div(class="flex items-center mb-6")
+                        div(class="w-12 h-12 bg-red-100 dark:bg-red-900 rounded-lg flex items-center justify-center mr-4")
+                            svg(class="w-6 h-6 text-red-600 dark:text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24")
+                                path(stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z")
+                        h2(class="text-2xl font-bold text-gray-800 dark:text-white") Обратная связь
+                    div
+                        FormValidator(
+                            :fields="{ name: true, email: true, phone: true, message: true }"
+                            buttonText="Отправить сообщение"
+                            @form-submitted="handleContactSubmit"
+                        )
+
+        div(class="mt-16 bg-white dark:bg-gray-800 rounded-2xl shadow-lg overflow-hidden animate-fade-in-up animation-delay-400")
+            div(class="h-64 bg-gray-300 dark:bg-gray-700")
+            div(class="p-8")
+                h3(class="text-2xl font-bold text-gray-800 dark:text-white mb-4") Как добраться
+                div(class="grid grid-cols-1 md:grid-cols-2 gap-6")
+                    div
+                        h4(class="text-lg font-semibold text-gray-800 dark:text-white mb-2") Общественным транспортом
+                        ul(class="space-y-2 text-gray-600 dark:text-gray-400")
+                            li Автобусы: 1, 2, 3, 4, 8, 12, 18
+                            li Маршрутки: 1, 2, 3, 4, 8, 12, 18, 27, 34
+                            li Остановка: "Кохи Борбад"
+                    div
+                        h4(class="text-lg font-semibold text-gray-800 dark:text-white mb-2") На автомобиле
+                        p(class="text-gray-600 dark:text-gray-400") Концертный зал расположен в центре города, рядом с озером "Кӯли ҷавонон". Имеется парковка для посетителей.
+
+        div(class="text-center mt-16")
+            div(class="bg-gradient-to-r from-accent to-yellow-600 rounded-2xl p-12 text-white animate-fade-in-up animation-delay-500")
+                h3(class="text-2xl md:text-3xl font-bold mb-4") Посетите наш концертный зал
+                p(class="text-xl mb-6 text-yellow-100") Мы ждем вас по адресу просп. Исмоила Сомони, 26
+                div(class="flex flex-col sm:flex-row gap-4 justify-center")
+                    button(
+                        @click="showOnMap"
+                        class="bg-white text-accent px-8 py-3 rounded-lg font-semibold hover:bg-gray-100 transition-colors"
+                    ) Показать на карте
+                    button(
+                        @click="callPhone"
+                        class="border-2 border-white text-white px-8 py-3 rounded-lg font-semibold hover:bg-white hover:text-accent transition-colors"
+                    ) Позвонить нам

+ 72 - 0
vue/app/pages/Contacts/index.styl

@@ -0,0 +1,72 @@
+// vue/app/pages/Contacts/index.styl
+// Стили исключительно для страницы контактов
+
+.contacts-section
+    .contact-card
+        transition: all 0.3s ease
+        
+        &:hover
+            transform: translateY(-5px)
+            box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)
+
+    .working-hours
+        .hour-item
+            transition: all 0.3s ease
+            border-bottom: 1px solid #e5e7eb
+            
+            .dark &
+                border-bottom-color: #374151
+            
+            &:last-child
+                border-bottom: none
+            
+            &:hover
+                background-color: rgba(0, 0, 0, 0.02)
+                
+                .dark &
+                    background-color: rgba(255, 255, 255, 0.02)
+
+    .transport-list
+        li
+            position: relative
+            padding-left: 1rem
+            
+            &::before
+                content: '•'
+                position: absolute
+                left: 0
+                color: #d69e2e
+
+// Адаптивность для мобильных устройств
+@media (max-width: 768px)
+    .contacts-section
+        .grid
+            gap: 1rem
+            
+        .bg-white, .bg-gray-800
+            padding: 1.5rem
+            
+        .text-4xl
+            font-size: 2.25rem
+            line-height: 2.5rem
+
+// Анимации для контактных карточек
+@keyframes contactCardAppear
+    from
+        opacity: 0
+        transform: translateX(-50px)
+    to
+        opacity: 1
+        transform: translateX(0)
+
+.contact-card
+    animation: contactCardAppear 0.6s ease forwards
+    
+    &:nth-child(1)
+        animation-delay: 0.1s
+    &:nth-child(2)
+        animation-delay: 0.2s
+    &:nth-child(3)
+        animation-delay: 0.3s
+    &:nth-child(4)
+        animation-delay: 0.4s