|
|
hai 3 semanas | |
|---|---|---|
| assets | hai 3 semanas | |
| pug | hai 3 semanas | |
| scripts | hai 3 semanas | |
| vue | hai 3 semanas | |
| .gitignore | hai 3 semanas | |
| README.md | hai 3 semanas | |
| doc.json | hai 3 semanas | |
| lzma.coffee | hai 3 semanas |
Доработай https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/src/master/vue/app/pages/Page с учётом изменений в сструктуре хранимых данных, для объекта страниц. в https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/README.md продумай создание структуры траницы с подключаемыми компанентами, в теле markdown текста.
https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/README.md
https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/README.md
не используем EventBus, в место него используем _. смотри описание Глобальные переменные состояния приложения из файла https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/README.md
для анализа кода бери версии файлов СТРОГО из репозитария: https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/src/master , корневой каталог vue/ от него идут пути к файлам пример: в коде -> app/temp.coffee, в репозитарии -> vue/app/temp.coffee
a(href="[ссылка]") - не правильно router-link(to="[ссылка]") - не правильно app-link(to="[ссылка]") - правильно (должен быть подключен компанент: 'app-link': require 'app/shared/AppLink')
Важно: мета данные добавляются через app/temp.coffe базовым тегоьм для vuejs является body, app/index.pug начинается с div, теги html, head, body ЗАПРЕЩЕНО использовать.
# обязательно подключение глобальных массивов
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 {
appState:
events: []
featuredEvents: []
sliderEvents: []
loading: true
error: null
modalState: #управление модальными окнами
isVisible: false
component: null
props: {}
couchDBService: new CouchDBService()
}
beforeMount: ()->
debug.log "start beforeMount"
# определение контекста vuejs приложения как глобальной переменной _
globalThis._ = @
# все глобальные переменные необходимые для работы определяем в data
# и получаем доступ через _.*
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')
# Важно загрузка стилей компонента/страницы
document.head.insertAdjacentHTML('beforeend','<style type="text/tailwindcss" page="Blog">'+stylFns['app/pages/Blog/index.styl']+'</style>')
module.exports =
name: 'BlogPage'
# ВАЖНО загрузка шаблона через рендер функцию
render: (new Function '_ctx', '_cache', renderFns['app/pages/Blog/index.pug'])()
data: ->
posts: []
loading: true
error: null
beforeMount: ->
@loadBlogPosts()
methods:
loadBlogPosts: ->
try
@loading = true
@posts = await AppDB.getBlogPosts(limit: 10)
@loading = false
catch error
@error = "Ошибка загрузки постов: "+error
@loading = false
при обновлении документа учитывай версионность
# Design документ для блог постов
blog_posts:
version: "1.1"
views:
# Все опубликованные блог посты
published:
map: ((doc) ->
if doc.type is 'blog_post' and doc.status is 'published'
emit(doc.created_at, doc)).toString()
debug = require('../../../utils/coffee/debug.coffee').default
template(#body) - не правильно template(v-slot:body) - не правильно template([body]) - правильно
async loadData: -> - не правильно loadData: -> - правильно
всегда приводи полный листинг файлов при форматировании кода для отделения логических блоков используй 4 пробела (" ") следи за строгим соблюдением синтаксиса используемых языков (coffeescript, pug, stylus) в pug не используй многострочные вычисляемые атрибуты
:class="{
'bg-blue-50 dark:bg-blue-900 text-blue-600 dark:text-blue-400': currentLanguage === language.code,
'text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700': currentLanguage !== language.code
}"
не правильно
:class="{'bg-blue-50 dark:bg-blue-900 text-blue-600 dark:text-blue-400': currentLanguage === language.code, 'text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700': currentLanguage !== language.code }"
используй для вывода в консоль debug.log console.log "переменная temp = #{temp}" - не правильно debug.log "переменная temp = "+temp - правильно
shareUrl = "https://twitter.com/intent/tweet?text=#{text}" - не правильно shareUrl = "https://twitter.com/intent/tweet?text="+text - правильно
"#{@baseUrl}/#{@dbName}/_all_docs?include_docs=true" - не правильно @baseUrl+"/"+@dbName+"/_all_docs?include_docs=true" - правильно
во всех *.styl файлах используй цвета в виде переменных, определённых в файле tailwind.config.js
все глобальный настройки стилей, пиши в app/temp.styl в остальных файлах, строго стили необходимые только для данного компаонента
img(src="/images/hall-interior.jpg") - не правильно img(src="/assets/[domenName]/hall-interior.jpg") - правильно
.container.mx-auto.px-4 - не правильно div(class="container.mx-auto px-4") - правильно
Vue = require 'vue' VueRouter = require 'vue-router'
Универсаньная CMS для работы с couchdb как бекендом. CMS мультидоменная и мультиязычная. мультидоменность во все view через поле domain
app/ ├── tailwind.config.js (настройка тем и Tailwind CSS) ├── temp.pug (основной layout) ├── temp.coffee (инициализация Vue и роутера) ├── temp.styl (стили которые сложно или не удобно сделать на Tailwind CSS или стили к однотипным элементам на stylus) ├── core/ - Каталог для хранения coffee файлов частей ядра системы, для улучшения чтения temp.coffee | ├── CouchdbClass.coffee | ... ├── page/ | ├── pages/ (универсальный компонент для отображения страниц сайта) | | ├── index.coffee | | ├── index.pug | | ├── index.styl | ├── blog/ (компонент для отображения главной страницы блога) | | ├── index.coffee | | ├── index.pug | | ├── index.styl | ├── [другие_компоненты]/ (компоненты для отображения страниц, специаьного типа (События, Продукты...)) | ├── index.coffee | ├── index.pug | ├── index.styl └── shared/
├── AppLink/ ( описание: https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/vue/app/shared/AppLink/README.md)
| ├── README.md
| ├── index.coffee
| ├── index.pug
| ├── index.styl
├── ThemeToggle/ ( описание: https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/vue/app/shared/ThemeToggle/README.md)
| ├── index.coffee
| ├── index.pug
| ├── index.styl
├── LanguageSwitcher/ ( описание: https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/vue/app/shared/LanguageSwitcher/README.md)
| ├── index.coffee
| ├── index.pug
| ├── index.styl
├── MultiLevelMenu/ ( описание: https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/vue/app/shared/MultiLevelMenu/README.md)
| ├── index.coffee
| ├── index.pug
| ├── index.styl
├── ImageSlider/ ( описание: https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/vue/app/shared/ImageSlider/README.md)
| ├── index.coffee
| ├── index.pug
| ├── index.styl
├── ModalWindow/ ( описание: https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/vue/app/shared/ModalWindow/README.md)
| ├── index.coffee
| ├── index.pug
| ├── index.styl
├── FormValidator/ ( описание: https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/vue/app/shared/FormValidator/README.md)
| ├── index.coffee
| ├── index.pug
| ├── index.styl
├── FilterSort/ ( описание: https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/vue/app/shared/FilterSort/README.md)
├── index.coffee
├── index.pug
├── index.styl
_# В app/temp.coffee - данные приложения
data: ()->
return
# Состояние загрузки и ошибок
dbReady: false
loading: true
error: null
# Языковые настройки
currentLanguage: 'ru'
availableLanguages: ['ru', 'en', 'tj']
# Тема оформления
currentTheme: 'light' # 'light' | 'dark' | 'auto'
availableThemes: ['light', 'dark', 'auto']
# Глобальное состояние приложения
appState:
slides: []
featuredEvents: []
blogPosts: []
products: []
categories: []
loading: true
error: null
# Состояние модальных окон
modalState:
isVisible: false
component: null
props: {}
# Состояние меню
menuState:
isOpen: false
activeMenu: null
breadcrumbs: []
# Состояние фильтров и сортировки
filterState:
activeFilters: {}
sortBy: 'created_at'
sortOrder: 'desc'
searchQuery: ''
# Состояние форм
formState:
submitting: false
errors: {}
touched: {}
Файл: vue/app/shared/AppLink/README.md
Зависимости от _:
router-link для внутренних ссылокМетоды использования:
app-link(to="/about") О нас
app-link(to="https://example.com" target="_blank") Внешняя ссылка
app-link(:to="{ name: 'EventDetail', params: { id: event._id } }") Детали
Файл: vue/app/shared/ThemeToggle/README.md
Зависимости от _:
# Необходимые глобальные переменные:
_.currentTheme # Текущая тема ('light', 'dark', 'auto')
_.availableThemes # Доступные темы
# Необходимые методы:
_.changeTheme(theme) # Метод для смены темы
Реализация в temp.coffee:
methods:
changeTheme: (theme) ->
if theme in @availableThemes
@currentTheme = theme
# Сохранение в localStorage
localStorage.setItem('theme', theme)
# Применение темы к документу
if theme is 'dark' or (theme is 'auto' and window.matchMedia('(prefers-color-scheme: dark)').matches)
document.documentElement.classList.add('dark')
else
document.documentElement.classList.remove('dark')
Файл: vue/app/shared/LanguageSwitcher/README.md
Зависимости от _:
# Необходимые глобальные переменные:
_.currentLanguage # Текущий язык ('ru', 'en', 'tj')
_.availableLanguages # Доступные языки
# Необходимые методы:
_.changeLanguage(lang) # Метод для смены языка
Реализация в temp.coffee:
methods:
changeLanguage: (language) ->
if language in @availableLanguages
@currentLanguage = language
AppDB.multilingual.setLanguage(language)
# Сохранение в localStorage
localStorage.setItem('language', language)
# Перезагрузка данных с новым языком
@loadInitialData()
Файл: vue/app/shared/MultiLevelMenu/README.md
Зависимости от _:
# Необходимые глобальные переменные:
_.menuState.isOpen # Открыто ли меню
_.menuState.activeMenu # Активный пункт меню
_.menuState.breadcrumbs # Хлебные крошки
_.appState.categories # Категории для меню
_.currentLanguage # Текущий язык для мультиязычных названий
# Необходимые методы:
_.toggleMenu() # Переключение видимости меню
_.setActiveMenu(menuId) # Установка активного меню
Реализация в temp.coffee:
methods:
toggleMenu: ->
@menuState.isOpen = !@menuState.isOpen
setActiveMenu: (menuId) ->
@menuState.activeMenu = menuId
# Обновление хлебных крошек на основе активного меню
Файл: vue/app/shared/ImageSlider/README.md
Зависимости от _:
# Необходимые глобальные переменные:
_.appState.slides # Массив слайдов
_.currentLanguage # Текущий язык для мультиязычного контента
# Необходимые методы:
_.getText(textArray) # Получение текста для текущего языка
Пример данных слайдов:
slides: [
{
title: ["Заголовок слайда", "Slide title"]
content: ["Описание слайда", "Slide description"]
image: "/assets/slide1.jpg"
button_text: ["Узнать больше", "Learn more"]
button_link: ["/about", "/about"]
}
]
Файл: vue/app/shared/ModalWindow/README.md
Зависимости от _:
# Необходимые глобальные переменные:
_.modalState.isVisible # Видимость модального окна
_.modalState.component # Компонент для отображения
_.modalState.props # Props для компонента
# Необходимые методы:
_.openModal(component, props) # Открытие модального окна
_.closeModal() # Закрытие модального окна
Реализация в temp.coffee:
methods:
openModal: (component, props = {}) ->
@modalState.component = component
@modalState.props = props
@modalState.isVisible = true
closeModal: ->
@modalState.isVisible = false
@modalState.component = null
@modalState.props = {}
Файл: vue/app/shared/FormValidator/README.md
Зависимости от _:
# Необходимые глобальные переменные:
_.formState.submitting # Статус отправки формы
_.formState.errors # Ошибки валидации
_.formState.touched # Поля, которые были изменены
# Необходимые методы:
_.validateForm(formData, rules) # Валидация формы
_.resetForm() # Сброс формы
Реализация в temp.coffee:
methods:
validateForm: (formData, rules) ->
errors = {}
for field, rule of rules
if rule.required and not formData[field]
errors[field] = "Поле обязательно для заполнения"
if rule.minLength and formData[field]?.length < rule.minLength
errors[field] = "Минимальная длина: "+rule.minLength
@formState.errors = errors
return Object.keys(errors).length === 0
resetForm: ->
@formState.errors = {}
@formState.touched = {}
@formState.submitting = false
Файл: vue/app/shared/FilterSort/README.md
Зависимости от _:
# Необходимые глобальные переменные:
_.filterState.activeFilters # Активные фильтры
_.filterState.sortBy # Поле сортировки
_.filterState.sortOrder # Порядок сортировки
_.filterState.searchQuery # Поисковый запрос
_.currentLanguage # Текущий язык для фильтров
# Необходимые методы:
_.applyFilters(filters) # Применение фильтров
_.clearFilters() # Очистка фильтров
_.setSort(field, order) # Установка сортировки
Реализация в temp.coffee:
methods:
applyFilters: (filters) ->
@filterState.activeFilters = { ...@filterState.activeFilters, ...filters }
# Обновление отображаемых данных
@loadFilteredData()
clearFilters: ->
@filterState.activeFilters = {}
@filterState.searchQuery = ''
@loadFilteredData()
setSort: (field, order = 'desc') ->
@filterState.sortBy = field
@filterState.sortOrder = order
@loadFilteredData()
# ... imports and initial setup ...
app = Vue.createApp
name: 'app'
data: ()->
return
# Состояние инициализации
dbReady: false
loading: true
error: null
# Языковые настройки
currentLanguage: localStorage.getItem('language') || 'ru'
availableLanguages: ['ru', 'en', 'tj']
# Тема оформления
currentTheme: localStorage.getItem('theme') || 'auto'
availableThemes: ['light', 'dark', 'auto']
# Глобальное состояние приложения
appState:
slides: []
featuredEvents: []
blogPosts: []
products: []
categories: []
loading: true
error: null
# Состояние UI компонентов
modalState:
isVisible: false
component: null
props: {}
menuState:
isOpen: false
activeMenu: null
breadcrumbs: []
filterState:
activeFilters: {}
sortBy: 'created_at'
sortOrder: 'desc'
searchQuery: ''
formState:
submitting: false
errors: {}
touched: {}
# Пользовательские настройки
userPreferences:
notifications: true
fontSize: 'medium'
reduceMotion: false
beforeMount: ()->
debug.log "start beforeMount"
globalThis._ = @
# Применяем сохраненную тему
@applyTheme(@currentTheme)
# Инициализация базы данных
AppDB.initialize().then =>
@dbReady = true
@loadInitialData()
methods:
# Управление темой
changeTheme: (theme) ->
if theme in @availableThemes
@currentTheme = theme
localStorage.setItem('theme', theme)
@applyTheme(theme)
applyTheme: (theme) ->
if theme is 'dark' or (theme is 'auto' and window.matchMedia('(prefers-color-scheme: dark)').matches)
document.documentElement.classList.add('dark')
else
document.documentElement.classList.remove('dark')
# Управление языком
changeLanguage: (language) ->
if language in @availableLanguages
@currentLanguage = language
AppDB.multilingual.setLanguage(language)
localStorage.setItem('language', language)
@loadInitialData()
# Управление меню
toggleMenu: ->
@menuState.isOpen = !@menuState.isOpen
setActiveMenu: (menuId) ->
@menuState.activeMenu = menuId
# Управление модальными окнами
openModal: (component, props = {}) ->
@modalState.component = component
@modalState.props = props
@modalState.isVisible = true
closeModal: ->
@modalState.isVisible = false
@modalState.component = null
@modalState.props = {}
# Управление фильтрами
applyFilters: (filters) ->
@filterState.activeFilters = { ...@filterState.activeFilters, ...filters }
@loadFilteredData()
clearFilters: ->
@filterState.activeFilters = {}
@filterState.searchQuery = ''
@loadFilteredData()
setSort: (field, order = 'desc') ->
@filterState.sortBy = field
@filterState.sortOrder = order
@loadFilteredData()
# Управление формами
validateForm: (formData, rules) ->
errors = {}
for field, rule of rules
if rule.required and not formData[field]
errors[field] = @getText(["Поле обязательно для заполнения", "Field is required"])
if rule.minLength and formData[field]?.length < rule.minLength
errors[field] = @getText(["Минимальная длина: ", "Minimum length: "]) + rule.minLength
@formState.errors = errors
return Object.keys(errors).length === 0
resetForm: ->
@formState.errors = {}
@formState.touched = {}
@formState.submitting = false
# Вспомогательные методы
getText: (textArray) ->
return AppDB.multilingual.getText(textArray, '')
# Загрузка данных
loadInitialData: ->
@appState.loading = true
Promise.all([
@loadSlides()
@loadFeaturedEvents()
@loadBlogPosts()
@loadCategories()
]).then =>
@appState.loading = false
.catch (error) =>
@appState.error = error
@appState.loading = false
loadFilteredData: ->
# Реализация загрузки данных с учетом фильтров
pass
# ... остальные методы загрузки данных ...
# ... render, components, router ...
# app/shared/ThemeToggle/index.coffee
module.exports =
name: 'ThemeToggle'
computed:
currentTheme: ->
return _.currentTheme
availableThemes: ->
return _.availableThemes
methods:
changeTheme: (theme) ->
_.changeTheme(theme)
Базовый объект "Запись блога" (blog_post)
coffee
{
_id: "blog_post_season_opening_2024_borbad"
type: "blog_post"
domain: ["borbad.s5l.ru", "global"] # определяет приоритет доменов по порядку
language: ["ru", "en"] # поддерживаемые языки в порядке domain_priority
title: ["Открытие нового сезона 2024", "Opening of the new season 2024"]
content: ["# Добро пожаловать в новый творческий сезон!...", "# Welcome to the new creative season!..."]
excerpt: ["Новый творческий сезон 2024 года в концертном зале Борбад", "A new creative season in 2024 at the Borbad Concert Hall"]
seo: {
description: ["Концертный зал Борбад - культурный центр Душанбе", "Borbad Concert Hall - Dushanbe Cultural Center"]
keywords: [["концерты", "мероприятия", "Душанбе", "культура"], ["concerts", "events", "Dushanbe", "culture"]]
title: ["Открытие нового сезона 2024 - Кохи Борбад", "Opening of the new season 2024 - Borbad Concert Hall"]
}
image: ["/assets/borbad.s5l.ru/posts/season-opening.jpg", "/assets/borbad.s5l.ru/posts/season-opening.jpg"]
gallery: [[
"/assets/borbad.s5l.ru/gallery/post1.jpg"
"/assets/borbad.s5l.ru/gallery/post2.jpg"
], [
"/assets/borbad.s5l.ru/gallery/post1.jpg"
"/assets/borbad.s5l.ru/gallery/post2.jpg"
]]
tags: [["новости", "сезон", "анонс"], ["news", "season", "announcement"]]
category_id: "category_news_borbad" # ID конечной категории
category_path: ["category_news_borbad"] # Полный путь категории
author: ["Администрация Борбад", "Borbad Administration"]
status: "published" # published | draft | archived
featured: true
reading_time: [5, 5] # Время чтения в минутах для каждого языка
created_at: "2024-01-15T10:00:00.000Z"
updated_at: "2024-01-15T10:00:00.000Z"
published_at: "2024-01-15T10:00:00.000Z"
views: 156
likes: 23
shares: 45
}
Наследник "Страница" (page) - расширяет blog_post
coffee
{
_id: "page_about_borbad"
type: "page"
domain: ["borbad.s5l.ru", "global"]
language: ["ru", "en", "tj"]
title: ["О нас - Кохи Борбад", "About Us - Borbad", "Дар бораи мо - Борбад"]
content: [
"# О нашем концертном зале\n\n[component name=\"HeroSection\" props='{\"title\": \"Добро пожаловать в Борбад\", \"image\": \"/assets/borbad.s5l.ru/about-hero.jpg\"}']\n\nИстория нашего зала начинается с 2010 года...\n\n[component name=\"ImageGallery\" props='{\"images\": [\"/assets/gallery/1.jpg\", \"/assets/gallery/2.jpg\"]}']\n\n## Наша миссия\n\nМы создаем пространство для культуры и искусства.",
"# About Our Concert Hall\n\n[component name=\"HeroSection\" props='{\"title\": \"Welcome to Borbad\", \"image\": \"/assets/borbad.s5l.ru/about-hero.jpg\"}']\n\nOur hall's history began in 2010...\n\n[component name=\"ImageGallery\" props='{\"images\": [\"/assets/gallery/1.jpg\", \"/assets/gallery/2.jpg\"]}']\n\n## Our Mission\n\nWe create space for culture and art."
]
excerpt: ["Информация о концертном зале Борбад", "Information about Borbad Concert Hall", "Маълумот дар бораи ҳолли консертии Борбад"]
seo: {
description: ["Концертный зал Борбад - история и миссия", "Borbad Concert Hall - history and mission", "Ҳолли консертии Борбад - таърих ва вазифа"]
keywords: [["о нас", "история", "миссия"], ["about", "history", "mission"], ["дар бораи мо", "таърих", "вазифа"]]
title: ["О нас - Кохи Борбад", "About Us - Borbad", "Дар бораи мо - Борбад"]
}
image: [
"/assets/borbad.s5l.ru/pages/about.jpg"
"/assets/borbad.s5l.ru/pages/about.jpg"
"/assets/borbad.s5l.ru/pages/about.jpg"
]
gallery: [[], [], []]
tags: [["страница", "о нас"], ["page", "about"], ["саҳифа", "дар бораи мо"]]
category_id: "category_pages_borbad"
category_path: ["category_pages_borbad"]
author: ["Администрация Борбад", "Borbad Administration", "Маъмурияти Борбад"]
status: "published"
featured: false
template: "default"
parent_id: null
order: 1
protected: false
show_in_sitemap: true
allow_comments: false
created_at: "2024-01-15T10:00:00.000Z"
updated_at: "2024-01-15T10:00:00.000Z"
published_at: "2024-01-15T10:00:00.000Z"
views: 0
}
Наследник "Событие" (event) - расширяет blog_post
coffee
{
_id: "event_beethoven_concert_2024_03_borbad"
type: "event" # Наследует от blog_post
domain: ["borbad.s5l.ru", "concert-hall.tj"]
language: ["ru", "en", "tj"]
title: ["Симфонический концерт: Бетховен и Чайковский", "Symphonic Concert: Beethoven and Tchaikovsky", "Консерти симфонӣ: Бетховен ва Чайковский"]
content: ["# Великие композиторы\n\n## Программа концерта...", "# Great Composers\n\n## Concert Program...", "# Оҳангсозони бузург\n\n## Барномаи консерт..."]
excerpt: ["Симфонический концерт с произведениями Бетховена и Чайковского", "Symphonic concert with works by Beethoven and Tchaikovsky", "Консерти симфонӣ бо осори Бетховен ва Чайковский"]
seo: {
description: ["Симфонический концерт в зале Борбад - классическая музыка", "Symphonic concert at Borbad Hall - classical music", "Консерти симфонӣ дар ҳолли Борбад - мусиқии классикӣ"]
keywords: [["концерт", "симфоническая музыка", "классика"], ["concert", "symphonic music", "classical"], ["консерт", "мусиқии симфонӣ", "классикӣ"]]
}
image: ["/assets/borbad.s5l.ru/events/beethoven-concert.jpg", "/assets/borbad.s5l.ru/events/beethoven-concert.jpg", "/assets/borbad.s5l.ru/events/beethoven-concert.jpg"]
gallery: [[
"/assets/borbad.s5l.ru/gallery/concert1.jpg"
"/assets/borbad.s5l.ru/gallery/concert2.jpg"
], [
"/assets/borbad.s5l.ru/gallery/concert1.jpg"
"/assets/borbad.s5l.ru/gallery/concert2.jpg"
], [
"/assets/borbad.s5l.ru/gallery/concert1.jpg"
"/assets/borbad.s5l.ru/gallery/concert2.jpg"
]]
tags: [["концерт", "симфоническая музыка", "классика"], ["concert", "symphonic music", "classical"], ["консерт", "мусиқии симфонӣ", "классикӣ"]]
category_id: "category_classical_music_concerts_events_borbad"
category_path: ["category_events_borbad", "category_concerts_events_borbad", "category_classical_music_concerts_events_borbad"]
author: ["Симфонический оркестр Борбад", "Borbad Symphony Orchestra", "Оркестри симфонии Борбад"]
status: "published"
featured: true
# Дополнительные поля для событий
event_data: {
event_date: "2024-03-20T19:00:00.000Z" # Дата и время начала
end_date: "2024-03-20T21:00:00.000Z" # Дата и время окончания
location: ["Большой зал", "Main Hall", "Ҳолли асосӣ"]
venue_id: "venue_main_hall_borbad"
address: {
street: ["пр. Рудаки 22", "Rudaki Ave 22", "хиёбони Рӯдакӣ 22"]
city: ["Душанбе", "Dushanbe", "Душанбе"]
country: ["Таджикистан", "Tajikistan", "Тоҷикистон"]
}
coordinates: {
lat: 38.5732
lng: 68.7734
}
price: [500, 500, 500] # Цена для каждого языка
currency: "TJS"
available_tickets: 45
total_tickets: 300
status: "upcoming" # upcoming | ongoing | completed | cancelled
registration_required: true
max_attendees: 300
age_restriction: ["6+", "6+", "6+"]
organizer: ["Симфонический оркестр Борбад", "Borbad Symphony Orchestra", "Оркестри симфонии Борбад"]
performers: [["Фаррух Саидов (дирижер)", "Солисты оркестра"], ["Farrukh Saidov (conductor)", "Orchestra soloists"], ["Фаррух Саидов (дирижёр)", "Солистони оркестр"]]
duration: 120 # Продолжительность в минутах
}
created_at: "2024-01-15T10:00:00.000Z"
updated_at: "2024-01-15T10:00:00.000Z"
published_at: "2024-01-15T10:00:00.000Z"
views: 289
}
Наследник "Товар" (product) - расширяет blog_post
coffee
{
_id: "product_tshirt_logo_2024_borbad"
type: "product" # Наследует от blog_post
domain: ["shop.borbad.s5l.ru", "borbad.s5l.ru"]
language: ["ru", "en"]
title: ["Футболка с логотипом Борбад", "Borbad Logo T-shirt"]
content: ["## Качественная хлопковая футболка\n\nРазмеры: S, M, L, XL...", "## High-quality cotton t-shirt\n\nSizes: S, M, L, XL..."]
excerpt: ["Фирменная футболка концертного зала с логотипом", "Official concert hall t-shirt with logo"]
seo: {
description: ["Футболка с логотипом концертного зала Борбад - сувениры", "T-shirt with Borbad concert hall logo - souvenirs"]
keywords: [["футболка", "сувениры", "мерч"], ["t-shirt", "souvenirs", "merch"]]
}
image: ["/assets/borbad.s5l.ru/products/tshirt.jpg", "/assets/borbad.s5l.ru/products/tshirt.jpg"]
gallery: [[
"/assets/borbad.s5l.ru/products/tshirt-front.jpg"
"/assets/borbad.s5l.ru/products/tshirt-back.jpg"
], [
"/assets/borbad.s5l.ru/products/tshirt-front.jpg"
"/assets/borbad.s5l.ru/products/tshirt-back.jpg"
]]
tags: [["одежда", "сувениры", "мерч"], ["clothing", "souvenirs", "merch"]]
category_id: "category_souvenirs_borbad"
category_path: ["category_shop_borbad", "category_souvenirs_borbad"]
author: ["Магазин Борбад", "Borbad Shop"]
status: "published"
featured: true
# Дополнительные поля для товаров
product_data: {
price: [250, 250] # Цена для каждого языка
currency: "TJS"
compare_price: [350, 350] # Старая цена
sku: "TSH-BRB-001"
inventory: 50
status: "available" # available | out_of_stock | discontinued
attributes: {
sizes: [["S", "M", "L", "XL"], ["S", "M", "L", "XL"]]
colors: [["белый", "черный", "красный"], ["white", "black", "red"]]
material: [["100% хлопок"], ["100% cotton"]]
brand: [["Борбад"], ["Borbad"]]
}
weight: 0.3 # Вес в кг
dimensions: {
length: 70
width: 50
height: 5
}
shipping: {
free_shipping: [false, false]
shipping_cost: [50, 50]
}
variants: [ # Варианты товара
{
sku: "TSH-BRB-001-W"
attributes: { size: "S", color: "белый" }
price: [250, 250]
inventory: 15
}
]
}
created_at: "2024-01-15T10:00:00.000Z"
updated_at: "2024-01-15T10:00:00.000Z"
published_at: "2024-01-15T10:00:00.000Z"
views: 134
}
Наследник "Слайдер" (slide) - расширяет blog_post
coffee
{
_id: "slide_01_borbad"
type: "slide" # Наследует от blog_post
domain: ["borbad.s5l.ru", "concert-hall.tj"]
language: ["ru", "en"]
title: ["Добро пожаловать в Кохи Борбад", "Welcome to Borbad Concert Hall"]
content: ["## Современный концертный зал в сердце Душанбе\n\nМесто, где встречаются искусство и культура", "## Modern concert hall in the heart of Dushanbe\n\nA place where art and culture meet"]
excerpt: ["Концертный зал Борбад - культурный центр Душанбе", "Borbad Concert Hall - Dushanbe Cultural Center"]
seo: {
description: ["Концертный зал Борбад в Душанбе", "Borbad Concert Hall in Dushanbe"]
}
image: ["/assets/borbad.s5l.ru/sliders/main-hall.jpg", "/assets/borbad.s5l.ru/sliders/main-hall.jpg"]
gallery: [[], []] # Для слайдера обычно не используется
tags: [["слайдер", "главная"], ["slider", "main"]]
category_id: "category_sliders_borbad"
category_path: ["category_sliders_borbad"]
author: ["Администрация Борбад", "Borbad Administration"]
status: "published"
featured: false
# Дополнительные поля для слайдеров
slide_data: {
order: 1
active: true
button_text: ["Узнать больше", "Learn More"]
button_link: ["/about", "/about"]
button_style: "primary" # primary | secondary | outline
text_color: ["#ffffff", "#ffffff"]
text_position: ["center", "center"] # left | center | right
overlay: [true, true]
overlay_opacity: [0.4, 0.4]
mobile_image: ["/assets/borbad.s5l.ru/sliders/main-hall-mobile.jpg", "/assets/borbad.s5l.ru/sliders/main-hall-mobile.jpg"]
start_date: "2024-01-01T00:00:00.000Z" # Дата начала показа
end_date: "2024-12-31T23:59:59.000Z" # Дата окончания показа
target_audience: [["all"], ["all"]] # all | registered | specific
}
created_at: "2024-01-01T00:00:00.000Z"
updated_at: "2024-01-15T10:00:00.000Z"
published_at: "2024-01-01T00:00:00.000Z"
views: 0 # Для слайдеров обычно не отслеживается
}
Категория (category) - иерархическая структура
coffee
{
_id: "category_classical_music_concerts_events_borbad"
type: "category"
domain: ["borbad.s5l.ru", "concert-hall.tj"]
language: ["ru", "en", "tj"]
name: ["Классическая музыка", "Classical Music", "Мусиқии классикӣ"]
slug: ["classical-music", "classical-music", "musiqii-klasikī"]
description: ["Симфонические концерты и классические произведения", "Symphonic concerts and classical works", "Консертҳои симфонӣ ва осори классикӣ"]
image: ["/assets/borbad.s5l.ru/categories/classical-music.jpg", "/assets/borbad.s5l.ru/categories/classical-music.jpg", "/assets/borbad.s5l.ru/categories/classical-music.jpg"]
icon: ["classical", "classical", "classical"]
parent_id: "category_concerts_events_borbad"
parent_path: ["category_events_borbad", "category_concerts_events_borbad"]
level: 2
order: 1
children_count: 0
meta_title: ["Классическая музыка - Кохи Борбад", "Classical Music - Borbad Concert Hall", "Мусиқии классикӣ - Ҳолли Борбад"]
meta_description: ["Симфонические концерты и классические произведения", "Symphonic concerts and classical works", "Консертҳои симфонӣ ва осори классикӣ"]
active: true
featured: true
show_in_menu: true
menu_order: 1
color: ["#3B82F6", "#3B82F6", "#3B82F6"]
created_at: "2024-01-15T10:00:00.000Z"
updated_at: "2024-01-15T10:00:00.000Z"
}
Настройки домена (domain_settings)
coffee
{
_id: "domain_settings_borbad_s5l_ru"
type: "domain_settings"
domain: "borbad.s5l.ru" # Уникальный домен
name: ["Кохи Борбад - Концертный зал Душанбе", "Borbad Concert Hall - Dushanbe"]
description: ["Официальный сайт концертного зала Борбад", "Official website of Borbad Concert Hall"]
active: true
priority: 1
theme: "borbad"
languages: ["ru", "en", "tj"] # Поддерживаемые языки
default_language: "ru"
timezone: "Asia/Dushanbe"
currency: "TJS"
settings: {
seo: {
title_template: ["{page} - Кохи Борбад", "{page} - Borbad Concert Hall"]
description: ["Концертный зал Борбад - культурный центр Душанбе", "Borbad Concert Hall - Dushanbe Cultural Center"]
keywords: [["концерты", "мероприятия", "Душанбе", "культура"], ["concerts", "events", "Dushanbe", "culture"]]
}
social: {
facebook: "https://facebook.com/borbad"
instagram: "https://instagram.com/borbad"
twitter: "https://twitter.com/borbad"
}
contact: {
address: ["г. Душанбе, пр. Рудаки 22", "Rudaki Ave 22, Dushanbe"]
phone: ["+992 37 123-45-67", "+992 37 123-45-67"]
email: ["info@borbad.s5l.ru", "info@borbad.s5l.ru"]
}
features: {
online_booking: true
multi_language: true
ecommerce: true
}
}
pages: {
urls: {
about: '/about'
contacts: '/contacts'
privacy: '/privacy'
terms: '/terms'
help: '/help'
}
strings: {
not_found: ['Страница не найдена', 'Page not found', 'Саҳифа ёфт нашуд']
back_to_home: ['Вернуться на главную', 'Back to home', 'Бозгашт ба саҳифаи асосӣ']
loading: ['Загрузка...', 'Loading...', 'Бор шуда истодааст...']
page_not_found_description: ['Запрашиваемая страница не существует или была перемещена', 'The requested page does not exist or has been moved', 'Саҳифаи дархостшуда вуҷуд надорад ё кӯчонида шудааст']
gallery: ['Галерея', 'Gallery', 'Галерея']
read_more: ['Читать далее', 'Read more', 'Бештар хонед']
share: ['Поделиться', 'Share', 'Мубодила']
}
}
created_at: "2024-01-15T10:00:00.000Z"
updated_at: "2024-01-15T10:00:00.000Z"
}
Пользователь (user)
coffee
{
_id: "user_admin_main"
type: "user"
domain: "global" # Глобальный пользователь
email: "admin@borbad.s5l.ru"
name: ["Администратор Борбад", "Borbad Administrator"]
role: "admin"
active: true
permissions: ["read", "write", "delete", "admin"]
profile: {
avatar: ["/assets/borbad.s5l.ru/avatars/admin.jpg", "/assets/borbad.s5l.ru/avatars/admin.jpg"]
phone: ["+992 37 123-45-67", "+992 37 123-45-67"]
position: ["Системный администратор", "System Administrator"]
bio: ["Ответственный за техническую часть сайта", "Responsible for the technical part of the site"]
}
preferences: {
language: "ru"
notifications: true
theme: "dark"
timezone: "Asia/Dushanbe"
}
security: {
last_password_change: "2024-01-01T00:00:00.000Z"
two_factor_enabled: true
login_attempts: 0
}
domains_access: ["borbad.s5l.ru", "concert-hall.tj"]
created_at: "2024-01-01T00:00:00.000Z"
updated_at: "2024-01-15T10:00:00.000Z"
last_login: "2024-01-15T09:30:00.000Z"
}
Заказ (order)
coffee
{
_id: "order_2024_001_borbad"
type: "order"
domain: "shop.borbad.s5l.ru"
language: ["ru", "en"]
user_id: "user_customer_ivanov"
status: "completed"
total: 1500
currency: "TJS"
items: [
{
product_id: "event_ticket_1"
name: ["Билет на симфонический концерт", "Ticket for symphonic concert"]
quantity: 2
price: 500
total: 1000
type: "ticket"
}
{
product_id: "product_tshirt_logo_2024_borbad"
name: ["Футболка с логотипом", "Logo t-shirt"]
quantity: 1
price: 500
total: 500
type: "product"
}
]
customer_info: {
name: ["Иван Иванов", "Ivan Ivanov"]
email: "ivan@example.com"
phone: ["+992 123-45-67", "+992 123-45-67"]
}
payment_info: {
method: "card"
transaction_id: "txn_123456"
status: "paid"
amount: 1500
currency: "TJS"
payment_date: "2024-01-15T14:00:00.000Z"
}
shipping_info: {
method: "pickup"
address: null
tracking_number: null
}
metadata: {
ip_address: "192.168.1.100"
user_agent: "Mozilla/5.0..."
source: "website"
}
created_at: "2024-01-15T13:45:00.000Z"
updated_at: "2024-01-15T14:00:00.000Z"
}
Аудит (audit_log)
coffee
{
_id: "audit_2024_001"
type: "audit_log"
domain: "global"
user_id: "user_admin_main"
action: "create"
resource_type: "blog_post"
resource_id: "blog_post_season_opening_2024_borbad"
description: ["Создана новая запись блога 'Открытие нового сезона 2024'", "Created new blog post 'Opening of the new season 2024'"]
ip_address: "192.168.1.1"
user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
language: "ru"
metadata: {
old_value: null
new_value: {
title: ["Открытие нового сезона 2024", "Opening of the new season 2024"]
status: "published"
}
changes: ["title", "status"]
}
created_at: "2024-01-15T10:00:00.000Z"
}
https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/scripts/design-documents.coffee