Rework frontend
This commit is contained in:
+43
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
|
||||
<h1 class="text-brand-primary text-2xl mb-3 mt-2 md:text-3xl font-semibold tracking-tight dark:text-white lg:text-[40px] lg:leading-tight">
|
||||
{{ header }}
|
||||
</h1>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: "AcademicJournalsTitle",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
header: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<component
|
||||
v-for="(filter, index) in filters"
|
||||
:key="index"
|
||||
:is="getComponent(filter.type)"
|
||||
:filter="filter"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import CategoryBadge from "@/componentss/features/additionalEducationPrograms/components/badges/CategoryBadge.vue";
|
||||
import FormBadge from "@/componentss/features/additionalEducationPrograms/components/badges/FormBadge.vue";
|
||||
export default {
|
||||
name: "AdditionalProgramBadge",
|
||||
components: {
|
||||
Link,
|
||||
CategoryBadge,
|
||||
FormBadge
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getComponent(type) {
|
||||
const componentMap = {
|
||||
category: 'CategoryBadge',
|
||||
form: 'FormBadge',
|
||||
};
|
||||
return componentMap[type] || null;
|
||||
},
|
||||
},
|
||||
props: {
|
||||
filters: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.additionalEducation.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Дополнительное образование', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="this.$inertia.page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ additionalEducationTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.additionalEducation.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Дополнительное образование', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="this.$inertia.page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ additionalEducationTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
|
||||
export default {
|
||||
name: "AdditionalProgramItemBreadcrumbs",
|
||||
components: {BasicIcon, Link, BreadcrumbsWrapper},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
additionalEducationTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.additionalEducation.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Дополнительное образование', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.additionalEducation.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Дополнительное образование', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
export default {
|
||||
name: "AdditionalProgramListBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
eventTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
|
||||
<h1 class="text-brand-primary text-2xl mb-3 mt-2 md:text-3xl font-semibold tracking-tight dark:text-white lg:text-[40px] lg:leading-tight">
|
||||
{{ header }}
|
||||
</h1>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: "AdditionalProgramTitle",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
header: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<select @change="handleChange" v-model="directionEdu" class="py-3 px-4 pe-9 block w-full border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none">
|
||||
<option selected value="">Все</option>
|
||||
<option v-for="direction in directions.data" :value="direction.slug">{{ direction.title }}</option>
|
||||
</select>
|
||||
</template>
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import {debounce} from "lodash";
|
||||
|
||||
export default {
|
||||
name: "LevelEduFilter",
|
||||
components: {
|
||||
BasicIcon,
|
||||
Link,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
directionEdu: this.direction_filter?.value || '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChange() {
|
||||
if (this.directionEdu === "") {
|
||||
this.clearFilter();
|
||||
} else {
|
||||
this.filter();
|
||||
}
|
||||
},
|
||||
filter: debounce(function () {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('page');
|
||||
url.searchParams.delete('direction');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
data: {
|
||||
direction: this.directionEdu,
|
||||
},
|
||||
});
|
||||
}, 200),
|
||||
clearFilter() {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('direction');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
props: {
|
||||
directions: {
|
||||
type: Object,
|
||||
},
|
||||
direction_filter: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<span v-if="this.filter.value !== null" class="inline-flex items-center gap-x-1.5 py-1.5 ps-3 pe-2 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
||||
|
||||
{{ (filter.value.length > 1) ? filter.value.length + ' категории' : filter.content[filter.value[0]].data.title }}
|
||||
<button @click.prevent="clearFilter" type="button" class="shrink-0 size-4 inline-flex items-center justify-center rounded-full hover:bg-blue-200 focus:outline-none focus:bg-blue-200 focus:text-blue-500">
|
||||
<span class="sr-only">Remove badge</span>
|
||||
<svg class="shrink-0 size-3" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 6 6 18"></path>
|
||||
<path d="m6 6 12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Link } from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: "CategoryBadge",
|
||||
components: { Link },
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
clearFilter() {
|
||||
let url = new URL(window.location.href);
|
||||
|
||||
// Создаем массив для хранения всех ключей, которые нужно удалить
|
||||
const keysToDelete = [];
|
||||
|
||||
// Перебираем все параметры и добавляем ключи, начинающиеся с 'category', в массив
|
||||
for (const [key] of url.searchParams) {
|
||||
if (key.startsWith(this.filter.param)) {
|
||||
keysToDelete.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
// Удаляем все ключи из массива
|
||||
keysToDelete.forEach(key => url.searchParams.delete(key));
|
||||
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
});
|
||||
},
|
||||
},
|
||||
props: {
|
||||
filter: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<span v-if="this.filter.value !== null" class="inline-flex items-center gap-x-1.5 py-1.5 ps-3 pe-2 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
||||
{{ filter.value }}
|
||||
<button @click.prevent="clearFilter" type="button" class="shrink-0 size-4 inline-flex items-center justify-center rounded-full hover:bg-blue-200 focus:outline-none focus:bg-blue-200 focus:text-blue-500">
|
||||
<span class="sr-only">Remove badge</span>
|
||||
<svg class="shrink-0 size-3" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 6 6 18"></path>
|
||||
<path d="m6 6 12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</span>
|
||||
</template>
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
export default {
|
||||
name: "FormBadge",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clearFilter() {
|
||||
let url = new URL(window.location.href);
|
||||
|
||||
// Создаем массив для хранения всех ключей, которые нужно удалить
|
||||
const keysToDelete = [];
|
||||
|
||||
// Перебираем все параметры и добавляем ключи, начинающиеся с 'category', в массив
|
||||
for (const [key] of url.searchParams) {
|
||||
if (key.startsWith(this.filter.param)) {
|
||||
keysToDelete.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
// Удаляем все ключи из массива
|
||||
keysToDelete.forEach(key => url.searchParams.delete(key));
|
||||
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
filter: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="min-w-[12rem] py-1 space-y-3">
|
||||
<button @click.prevent="clearFilter" class="text-gray-500 text-sm flex gap-x-1 items-center hover:text-gray-700">
|
||||
<BasicIcon class="w-4 h-4" name="delete" />
|
||||
<span>Очистить</span>
|
||||
</button>
|
||||
|
||||
<div class="divide-y divide-gray-200 dark:divide-gray-700 max-h-[30vh] overflow-y-auto">
|
||||
<div>
|
||||
<div class="flex flex-col ml-3">
|
||||
<div v-for="(budget, index) in budgets">
|
||||
<input v-model="budgetEdu" :value="index" @change="filter"
|
||||
type="radio" class="shrink-0 mt-0.5 border-gray-200 rounded-full text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none"
|
||||
:id="'inp-tag' + index">
|
||||
<label :for="'inp-tag' + index" class="text-sm text-gray-500 ms-3 dark:text-neutral-400">{{ budget }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import SearchBadge from "@/Components/BuilderUi/Events/Badges/SearchBadge.vue";
|
||||
import CategoryBadge from "@/Components/BuilderUi/Events/Badges/CategoryBadge.vue";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import {debounce} from "lodash";
|
||||
export default {
|
||||
name: "BudgetFilter",
|
||||
components: {
|
||||
BasicIcon,
|
||||
Link,
|
||||
SearchBadge,
|
||||
CategoryBadge
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
budgetEdu: this.budget_filter.value || [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
filter: debounce(function () {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('page');
|
||||
url.searchParams.delete('budget');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
data: {
|
||||
budget: this.budgetEdu,
|
||||
},
|
||||
});
|
||||
}, 500),
|
||||
clearFilter() {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('budget');
|
||||
this.budgetEdu = [];
|
||||
this.searchTerm = ''; // Сбросить поле поиска
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
props: {
|
||||
budgets: {
|
||||
type: Object,
|
||||
},
|
||||
budget_filter: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="min-w-[12rem] py-1 space-y-3">
|
||||
<button @click.prevent="clearFilter" class="text-gray-500 text-sm flex gap-x-1 items-center hover:text-gray-700">
|
||||
<BasicIcon class="w-4 h-4" name="delete" />
|
||||
<span>Очистить</span>
|
||||
</button>
|
||||
|
||||
<div class="divide-y divide-gray-200 dark:divide-gray-700 max-h-[30vh] overflow-y-auto">
|
||||
<div>
|
||||
<div class="flex flex-col ml-3">
|
||||
<div v-for="item in categories" :key="item.id">
|
||||
<input v-model="category" :value="item.slug" @change="filter"
|
||||
type="checkbox" class="shrink-0 mt-0.5 border-gray-200 rounded text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none"
|
||||
:id="'inp' + item.id">
|
||||
<label :for="'inp' + item.id" class="text-sm text-gray-500 ms-3 dark:text-neutral-400">{{ item.name }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import SearchBadge from "@/Components/BuilderUi/Events/Badges/SearchBadge.vue";
|
||||
import CategoryBadge from "@/Components/BuilderUi/Events/Badges/CategoryBadge.vue";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import {debounce} from "lodash";
|
||||
export default {
|
||||
name: "CategoryFilter",
|
||||
components: {
|
||||
BasicIcon,
|
||||
Link,
|
||||
SearchBadge,
|
||||
CategoryBadge
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
category: this.category_filter.value || [],
|
||||
searchTerm: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
filter: debounce(function () {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('page');
|
||||
url.searchParams.delete('category[]');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
data: {
|
||||
category: this.category,
|
||||
},
|
||||
});
|
||||
}, 500),
|
||||
clearFilter() {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('category[]');
|
||||
this.category = [];
|
||||
this.searchTerm = ''; // Сбросить поле поиска
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
props: {
|
||||
categories: {
|
||||
type: Object,
|
||||
},
|
||||
category_filter: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div class="min-w-[12rem] py-1 space-y-3">
|
||||
<button @click.prevent="clearFilter" class="text-gray-500 text-sm flex gap-x-1 items-center hover:text-gray-700">
|
||||
<BasicIcon class="w-4 h-4" name="delete" />
|
||||
<span>Очистить</span>
|
||||
</button>
|
||||
|
||||
<div class="divide-y divide-gray-200 dark:divide-gray-700 max-h-[30vh] overflow-y-auto">
|
||||
<div>
|
||||
<div class="flex flex-col ml-3">
|
||||
<div v-for="(form, index) in forms">
|
||||
<input v-model="formEdu" :value="index" @change="filter"
|
||||
type="radio" class="shrink-0 mt-0.5 border-gray-200 rounded-full text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none"
|
||||
:id="'inp-tag' + index">
|
||||
<label :for="'inp-tag' + index" class="text-sm text-gray-500 ms-3 dark:text-neutral-400">{{ form }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import {debounce} from "lodash";
|
||||
export default {
|
||||
name: "FormEducationalFilter",
|
||||
components: {
|
||||
BasicIcon,
|
||||
Link
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formEdu: this.formEdu_filter.value || [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
filter: debounce(function () {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('page');
|
||||
url.searchParams.delete('form');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
data: {
|
||||
form: this.formEdu,
|
||||
},
|
||||
});
|
||||
}, 500),
|
||||
clearFilter() {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('form');
|
||||
this.formEdu = [];
|
||||
this.searchTerm = ''; // Сбросить поле поиска
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
props: {
|
||||
forms: {
|
||||
type: Object,
|
||||
},
|
||||
formEdu_filter: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div class="min-w-[12rem] py-1 space-y-3">
|
||||
<h3 class="font-medium text-gray-900 text-sm mb-2">Сортировать по</h3>
|
||||
<div>
|
||||
<select @change="filter" v-model="sortOrder" class="py-2 px-3 pe-9 block w-full border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600">
|
||||
<option value="desc">Дате (Сначала новые)</option>
|
||||
<option value="asc">Дате (Сначала старые)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import SearchBadge from "@/Components/BuilderUi/Events/Badges/SearchBadge.vue";
|
||||
import CategoryBadge from "@/Components/BuilderUi/Events/Badges/CategoryBadge.vue";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import {debounce} from "lodash";
|
||||
export default {
|
||||
name: "SortingByFilter",
|
||||
components: {
|
||||
BasicIcon,
|
||||
Link,
|
||||
SearchBadge,
|
||||
CategoryBadge
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sortOrder: this.sortingBy_filter.value || 'desc',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
filter: debounce(function () {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('page');
|
||||
url.searchParams.delete('sort');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
data: {
|
||||
sort: this.sortOrder,
|
||||
},
|
||||
});
|
||||
}, 500),
|
||||
clearFilter() {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('sort');
|
||||
this.tag_slug = [];
|
||||
this.searchTerm = ''; // Сбросить поле поиска
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
props: {
|
||||
sortingBy_filter: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.faculty.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Факультеты', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.faculty.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Факультет', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="this.$inertia.page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ departmentTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.faculty.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Факультеты', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.faculty.show', faculty.slug)" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ faculty.title }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="this.$inertia.page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ departmentTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
export default {
|
||||
name: "DepartmentItemBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
departmentTitle: {
|
||||
type: String,
|
||||
},
|
||||
faculty: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
|
||||
<div class="flex flex-col rounded-xl p-4 md:p-6 bg-white border border-gray-200 dark:bg-slate-900 dark:border-gray-700">
|
||||
<div class="flex items-center gap-y-4 gap-x-4 flex-wrap md:flex-nowrap">
|
||||
<img v-if="teacher.photo" @click="toggler = !toggler" loading="lazy" class="rounded-xl md:w-[150px]" :src="'/storage/' + teacher.photo" alt="Image Description">
|
||||
<div class="grow">
|
||||
<Link :href="route('client.person.show', teacher.slug)" class="font-medium text-gray-800 hover:text-gray-500 underline">
|
||||
{{ teacher.position }}: {{ teacher.name }}
|
||||
</Link>
|
||||
<p v-if="teacher.academicTitle !== null" class="text-xs text-gray-500 mt-2">
|
||||
Ученая степень: {{ teacher.academicTitle }}
|
||||
</p>
|
||||
<p v-if="teacher.contactPhone" class="text-xs text-gray-500 mt-2">
|
||||
Контактный телефон: {{ teacher.contactPhone }}
|
||||
</p>
|
||||
<p v-if="teacher.contactEmail" class="text-xs text-gray-500 mt-2">
|
||||
Электронная почта: {{ teacher.contactEmail }}
|
||||
</p>
|
||||
<p v-if="teacher.cabinet" class="text-xs text-gray-500 mt-2">
|
||||
Кабинет: {{ teacher.cabinet }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FsLightbox class="" :toggler="toggler" :sources="['/storage/' + teacher.photo]"/>
|
||||
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
import {Head, Link} from "@inertiajs/vue3";
|
||||
import MainNavbar from "@/Navbars/MainNavbar.vue";
|
||||
import FsLightbox from "fslightbox-vue";
|
||||
export default {
|
||||
name: "DepartmentTeacherCard",
|
||||
data() {
|
||||
return {
|
||||
toggler: false,
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
teacher: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
MainNavbar,
|
||||
Link,
|
||||
FsLightbox,
|
||||
Head
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
|
||||
<div class="flex flex-col rounded-xl p-4 md:p-6 bg-white border border-gray-200">
|
||||
<div class="flex items-center gap-y-4 gap-x-4 flex-wrap md:flex-nowrap">
|
||||
<img v-if="worker.photo" @click="toggler = !toggler" loading="lazy" class="rounded-xl md:w-[150px]" :src="'/storage/' + worker.photo" alt="Image Description">
|
||||
<div class="grow">
|
||||
<Link :href="route('client.person.show', worker.slug)" class="font-medium text-gray-800 hover:text-gray-500 underline">
|
||||
{{ worker.position }}: {{ worker.name }}
|
||||
</Link>
|
||||
<p v-if="worker.academicTitle !== null" class="text-xs text-gray-500 mt-2">
|
||||
Ученая степень: {{ worker.academicTitle }}
|
||||
</p>
|
||||
<p v-if="worker.contactPhone" class="text-xs text-gray-500 mt-2">
|
||||
Контактный телефон: {{ worker.contactPhone }}
|
||||
</p>
|
||||
<p v-if="worker.contactEmail" class="text-xs text-gray-500 mt-2">
|
||||
Электронная почта: {{ worker.contactEmail }}
|
||||
</p>
|
||||
<p v-if="worker.cabinet" class="text-xs text-gray-500 mt-2">
|
||||
Кабинет: {{ worker.cabinet }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FsLightbox class="" :toggler="toggler" :sources="['/storage/' + worker.photo]"/>
|
||||
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
import {Head, Link} from "@inertiajs/vue3";
|
||||
import MainNavbar from "@/Navbars/MainNavbar.vue";
|
||||
import FsLightbox from "fslightbox-vue";
|
||||
export default {
|
||||
name: "DepartmentWorkerCard",
|
||||
data() {
|
||||
return {
|
||||
toggler: false,
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
worker: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
MainNavbar,
|
||||
Link,
|
||||
FsLightbox,
|
||||
Head
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.division.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Подразделения института', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="this.$inertia.page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ divisionTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.division.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Подразделения института', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="this.$inertia.page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ divisionTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
export default {
|
||||
name: "DivisionItemBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
divisionTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.program.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Образовательные программы', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.division.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Подразделения института', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
|
||||
export default {
|
||||
name: "DivisionListBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
eventTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div class="max-w-2xl text-center mx-auto mb-10 lg:mb-14">
|
||||
<h2 class="text-2xl font-bold md:text-4xl md:leading-tight dark:text-white">{{ header }}</h2>
|
||||
<p class="mt-1 text-gray-600 dark:text-neutral-400">{{ bottomText }}</p>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: "DivisionListTitle",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
header: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
bottomText: {
|
||||
type: String,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
|
||||
<div class="flex flex-col rounded-xl p-4 md:p-6 bg-white border border-gray-200 dark:bg-slate-900 dark:border-gray-700">
|
||||
<div class="flex items-center gap-y-4 gap-x-4 flex-wrap md:flex-nowrap">
|
||||
<img v-if="worker.photo" @click="toggler = !toggler" loading="lazy" class="rounded-xl md:w-[150px]" :src="'/storage/' + worker.photo" alt="Image Description">
|
||||
<div class="grow">
|
||||
<Link :href="route('client.person.show', worker.slug)" class="font-medium text-gray-800 hover:text-gray-500 underline">
|
||||
{{ worker.administrativePosition }}: {{ worker.name }}
|
||||
</Link>
|
||||
<p v-if="worker.academicTitle !== null" class="text-xs text-gray-500 mt-2">
|
||||
Ученая степень: {{ worker.academicTitle }}
|
||||
</p>
|
||||
<p v-if="worker.contactPhone" class="text-xs text-gray-500 mt-2">
|
||||
Контактный телефон: {{ worker.contactPhone }}
|
||||
</p>
|
||||
<p v-if="worker.contactEmail" class="text-xs text-gray-500 mt-2">
|
||||
Электронная почта: {{ worker.contactEmail }}
|
||||
</p>
|
||||
<p v-if="worker.cabinet" class="text-xs text-gray-500 mt-2">
|
||||
Кабинет: {{ worker.cabinet }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FsLightbox class="" :toggler="toggler" :sources="['/storage/' + worker.photo]"/>
|
||||
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
import {Head, Link} from "@inertiajs/vue3";
|
||||
import MainNavbar from "@/Navbars/MainNavbar.vue";
|
||||
import FsLightbox from "fslightbox-vue";
|
||||
export default {
|
||||
name: "DivisionWorkerCard",
|
||||
data() {
|
||||
return {
|
||||
toggler: false,
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
worker: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
MainNavbar,
|
||||
Link,
|
||||
FsLightbox,
|
||||
Head
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.program.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Образовательные программы', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="this.$inertia.page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ programTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.program.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Образовательные программы', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="this.$inertia.page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ programTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
|
||||
export default {
|
||||
name: "ProgramItemBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
programTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<select @change="filter" v-model="levelEdu" class="py-3 px-4 pe-9 block w-full border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none">
|
||||
<option @click.prevent="clearFilter" selected value="">Все</option>
|
||||
<option v-for="(level, key) in levels" :value="key">{{ level }}</option>
|
||||
</select>
|
||||
</template>
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
import {debounce} from "lodash";
|
||||
|
||||
export default {
|
||||
name: "ProgramLevelEduFilter",
|
||||
components: {
|
||||
Link,
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
levelEdu: this.level_filter.value || '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
filter: debounce(function () {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('page');
|
||||
url.searchParams.delete('level');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
data: {
|
||||
level: this.levelEdu,
|
||||
},
|
||||
});
|
||||
}, 500),
|
||||
clearFilter() {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('level');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
props: {
|
||||
levels: {
|
||||
type: Object,
|
||||
},
|
||||
level_filter: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.program.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Образовательные программы', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.program.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Образовательные программы', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
|
||||
export default {
|
||||
name: "ProgramListBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
eventTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
|
||||
<h1 class="text-brand-primary text-2xl mb-3 mt-2 md:text-3xl font-semibold tracking-tight dark:text-white lg:text-[40px] lg:leading-tight">
|
||||
{{ header }}
|
||||
</h1>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: "ProgramTitle",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
header: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.event.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
{{ textLimit('Мероприятия', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.event.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Мероприятия', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.event.archive')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Архив', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
export default {
|
||||
name: "EventArchiveListBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
eventTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.event.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Мероприятия', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="$page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ eventTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.event.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Мероприятия', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="$page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ eventTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
export default {
|
||||
name: "EventItemBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
eventTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.event.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
{{ textLimit('Мероприятия', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.event.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Мероприятия', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
export default {
|
||||
name: "EventListBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
eventTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
|
||||
<div class="">
|
||||
<!--Фильтр-->
|
||||
|
||||
<button type="button" class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none" aria-haspopup="dialog" aria-expanded="false" aria-controls="hs-offcanvas-example" data-hs-overlay="#hs-offcanvas-example">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 6h9.75M10.5 6a1.5 1.5 0 1 1-3 0m3 0a1.5 1.5 0 1 0-3 0M3.75 6H7.5m3 12h9.75m-9.75 0a1.5 1.5 0 0 1-3 0m3 0a1.5 1.5 0 0 0-3 0m-3.75 0H7.5m9-6h3.75m-3.75 0a1.5 1.5 0 0 1-3 0m3 0a1.5 1.5 0 0 0-3 0m-9.75 0h9.75" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
|
||||
<!--Конец Фильтра-->
|
||||
</div>
|
||||
<div id="hs-offcanvas-example" class="hs-overlay hs-overlay-open:translate-x-0 hidden -translate-x-full fixed top-0 start-0 transition-all duration-300 transform h-full max-w-xs w-full z-[80] bg-white border-e overflow-auto" role="dialog" tabindex="-1" aria-labelledby="hs-offcanvas-example-label">
|
||||
<div class="flex justify-between items-center py-3 px-4 border-b">
|
||||
<h3 id="hs-offcanvas-example-label" class="font-bold text-gray-800">
|
||||
Фильтры
|
||||
</h3>
|
||||
<button type="button" class="size-8 inline-flex justify-center items-center gap-x-2 rounded-full border border-transparent bg-gray-100 text-gray-800 hover:bg-gray-200 focus:outline-none focus:bg-gray-200 disabled:opacity-50 disabled:pointer-events-none" aria-label="Close" data-hs-overlay="#hs-offcanvas-example">
|
||||
<span class="sr-only">Close</span>
|
||||
<svg class="shrink-0 size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 6 6 18"></path>
|
||||
<path d="m6 6 12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<IsOnlineFilter :is_online_filter="is_online_filter" />
|
||||
<div class="hs-accordion-group">
|
||||
<div class="hs-accordion" :id="'id' + category_filter.type">
|
||||
<button class="hs-accordion-toggle hs-accordion-active:text-blue-600 py-3 inline-flex items-center gap-x-3 w-full font-semibold text-start text-gray-800 hover:text-gray-500 focus:outline-none focus:text-gray-500 rounded-lg disabled:opacity-50 disabled:pointer-events-none" aria-expanded="false" aria-controls="hs-basic-with-arrow-collapse-two">
|
||||
<svg class="hs-accordion-active:hidden block size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m6 9 6 6 6-6"></path>
|
||||
</svg>
|
||||
<svg class="hs-accordion-active:block hidden size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m18 15-6-6-6 6"></path>
|
||||
</svg>
|
||||
Категории
|
||||
<span v-if="category_filter.value" class="inline-flex items-center gap-x-1.5 py-1.5 px-3 rounded-md text-xs font-medium border border-gray-200 bg-white text-gray-800 shadow-sm dark:bg-neutral-900 dark:border-neutral-700 dark:text-white">{{ category_filter.value.length }}</span>
|
||||
|
||||
</button>
|
||||
<div id="hs-basic-with-arrow-collapse-two" class="hs-accordion-content hidden w-full overflow-hidden transition-[height] duration-300" role="region" :aria-labelledby="'id' + category_filter.type">
|
||||
<CategoryFilter :categories="categories" :category_filter="category_filter" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import CategoryFilter from "@/componentss/shared/filter/filters/CategoryFilter.vue";
|
||||
import IsOnlineFilter from "@/componentss/shared/filter/filters/IsOnlineFilter.vue";
|
||||
import SortingByFilter from "@/componentss/shared/filter/filters/SortingByFilter.vue";
|
||||
import TagFilter from "@/componentss/shared/filter/filters/TagFilter.vue";
|
||||
|
||||
export default {
|
||||
name: "EventListFilter",
|
||||
components: {IsOnlineFilter, SortingByFilter, TagFilter, CategoryFilter, BasicIcon},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
categories: {
|
||||
type: Object,
|
||||
},
|
||||
category_filter: {
|
||||
type: Object,
|
||||
},
|
||||
sortingBy_filter: {
|
||||
type: Object,
|
||||
},
|
||||
is_online_filter: {
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="sm:col-span-1 w-full">
|
||||
<label for="hs-as-table-product-review-search" class="sr-only">Поиск</label>
|
||||
<div class="relative">
|
||||
<input autocomplete="off" @input="search" v-model="searchInput" type="text"
|
||||
id="hs-as-table-product-review-search"
|
||||
name="hs-as-table-product-review-search"
|
||||
class="py-3 px-3 pl-11 block flex-1 w-full border-gray-200 shadow-sm rounded-md text-sm focus:z-10 focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
|
||||
placeholder="Поиск архивных мероприятий">
|
||||
<div
|
||||
class="absolute inset-y-0 left-0 flex items-center pointer-events-none pl-4">
|
||||
<svg class="h-4 w-4 text-gray-400" xmlns="http://www.w3.org/2000/svg"
|
||||
width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path
|
||||
d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { debounce } from "lodash";
|
||||
|
||||
export default {
|
||||
name: "EventListSearch",
|
||||
data() {
|
||||
return {
|
||||
searchInput: this.search_filter.value,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
search: debounce(function () {
|
||||
if(this.searchInput === "") {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('search');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl,{
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
replace: true,
|
||||
});
|
||||
} else {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('page');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl,{
|
||||
method: 'get',
|
||||
data: {
|
||||
search: this.searchInput,
|
||||
},
|
||||
preserveState: true,
|
||||
replace: true,
|
||||
})
|
||||
}
|
||||
}, 500),
|
||||
|
||||
},
|
||||
props: [
|
||||
'search_filter'
|
||||
],
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div class="relative rounded-xl overflow-auto">
|
||||
<div class="max-w-4xl mx-auto bg-white min-w-0">
|
||||
<div class="overflow-x-scroll flex no-scrollbar">
|
||||
<div class="flex items-center gap-x-3 whitespace-nowrap">
|
||||
<Link :href="route('client.event.archive')" class="text-[11px] text-center text-gray-500 hover:underline">Перейти <br> в архив</Link>
|
||||
<template v-for="eventMonth in dates">
|
||||
<div class="">
|
||||
<div class="flex flex-col items-center">
|
||||
<span class="text-[12px] text-gray-500">{{ eventMonth.month }}</span>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="flex">
|
||||
<template v-for="eventDate in eventMonth.events">
|
||||
<div class="flex flex-col items-center">
|
||||
<button :class="date === eventDate.date ? 'active-button' : ''" @click="filter(eventDate.date)" type="button" class="min-h-[38px] duration-300 ease-linear min-w-[38px] flex justify-center items-center text-gray-800 hover:bg-gray-100 py-2 px-3 text-sm rounded-lg focus:outline-none focus:bg-gray-100 disabled:opacity-50 disabled:pointer-events-none">{{ eventDate.day }}</button>
|
||||
<span class="text-[12px] text-gray-500">{{ eventDate.dayOfWeek }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
export default {
|
||||
name: "EventListSelectDate",
|
||||
components: {
|
||||
|
||||
Link,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
date: this.currentDate,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
filter(eventDate) {
|
||||
this.date = eventDate
|
||||
this.$inertia.reload( {
|
||||
data: {
|
||||
date: eventDate,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
dates: {
|
||||
type: Array,
|
||||
},
|
||||
currentDate: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Hide scrollbar for Chrome, Safari and Opera */
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hide scrollbar for IE, Edge and Firefox */
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
|
||||
.active-button {
|
||||
@apply bg-blue-600 text-white;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.faculty.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Факультеты', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="this.$inertia.page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ facultyTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.faculty.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Факультеты', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="this.$inertia.page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ facultyTitle }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
export default {
|
||||
name: "FacultyItemBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
facultyTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(this.breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(this.breadcrumbs.mainSection, this.breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(this.breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.faculty.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Факультеты', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.faculty.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Факультеты', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
export default {
|
||||
name: "FacultyListBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
eventTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div class="max-w-2xl text-center mx-auto mb-10 lg:mb-14">
|
||||
<h2 class="text-2xl font-bold md:text-4xl md:leading-tight dark:text-white">{{ header }}</h2>
|
||||
<p class="mt-1 text-gray-600 dark:text-neutral-400">{{ bottomText }}</p>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: "FacultyListTitle",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
header: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
bottomText: {
|
||||
type: String,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
|
||||
<div class="flex flex-col rounded-xl p-4 md:p-6 bg-white border border-gray-200 dark:bg-slate-900 dark:border-gray-700">
|
||||
<div class="flex items-center gap-y-4 gap-x-4 flex-wrap md:flex-nowrap">
|
||||
<img v-if="worker.photo" @click="toggler = !toggler" loading="lazy" class="rounded-xl md:w-[150px]" :src="'/storage/' + worker.photo" alt="Image Description">
|
||||
<div class="grow">
|
||||
<Link :href="route('client.person.show', worker.slug)" class="font-medium text-gray-800 hover:text-gray-500 underline">
|
||||
{{ worker.position }}: {{ worker.name }}
|
||||
</Link>
|
||||
<p v-if="worker.academicTitle !== null" class="text-xs text-gray-500 mt-2">
|
||||
Ученая степень: {{ worker.academicTitle }}
|
||||
</p>
|
||||
<p v-if="worker.contactPhone" class="text-xs text-gray-500 mt-2">
|
||||
Контактный телефон: {{ worker.contactPhone }}
|
||||
</p>
|
||||
<p v-if="worker.contactEmail" class="text-xs text-gray-500 mt-2">
|
||||
Электронная почта: {{ worker.contactEmail }}
|
||||
</p>
|
||||
<p v-if="worker.cabinet" class="text-xs text-gray-500 mt-2">
|
||||
Кабинет: {{ worker.cabinet }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FsLightbox class="" :toggler="toggler" :sources="['/storage/' + worker.photo]"/>
|
||||
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
import {Head, Link} from "@inertiajs/vue3";
|
||||
import MainNavbar from "@/Navbars/MainNavbar.vue";
|
||||
import FsLightbox from "fslightbox-vue";
|
||||
export default {
|
||||
name: "FacultyWorkerCard",
|
||||
data() {
|
||||
return {
|
||||
toggler: false,
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
worker: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
MainNavbar,
|
||||
Link,
|
||||
FsLightbox,
|
||||
Head
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(breadcrumbs.mainSection, breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('page.view', breadcrumbs.page.data.path)" class="flex items-center text-gray-500 hover:text-primaryBlue">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(breadcrumbs.page.data.title, 25) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(pageTitle, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
export default {
|
||||
name: "PageBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
pageTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="w-full h-[67px] fixed pointer-events-none bvi-no-styles" id="visor"></div>
|
||||
|
||||
<nav class="order-last hidden w-56 shrink-0 lg:block">
|
||||
<div v-if="headerNavs.length > 0" class="sticky top-[100px] h-[calc(100vh-121px)]">
|
||||
<div class="text-gray-1000 mb-2 text-md font-medium">На этой странице</div>
|
||||
<ul class="max-h-[70vh] space-y-1.5 overflow-hidden py-2 text-sm">
|
||||
<li class="anchor-li" v-for="pageNav in headerNavs" :key="pageNav.id">
|
||||
<a :class="{ 'translate-x-2 text-primaryBlue' : currentNavSection === generateSlug(pageNav.text), 'bg-transperant text-gray-600 hover:text-gray-900' : currentNavSection !== generateSlug(pageNav.text) }"
|
||||
class="duration-150 block py-1 px-2 leading-[1.6] rounded-md"
|
||||
:href="'#' + generateSlug(pageNav.text)">{{ pageNav.text }}</a>
|
||||
</li>
|
||||
<transition name="fade">
|
||||
<li class="anchor-li flex items-center py-2 border-t" v-if="scrollTop" @click.prevent="scrollToTop">
|
||||
<button class="bg-transperant text-gray-600 cursor-pointer hover:text-gray-900 duration-300 block px-2 leading-[1.6] rounded-md">К началу</button>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-[17px] text-gray-600">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 11.25l-3-3m0 0l-3 3m3-3v7.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</li>
|
||||
</transition>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Link } from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: "PageNavigateLinks",
|
||||
components: { Link },
|
||||
data() {
|
||||
return {
|
||||
currentNavSection: null,
|
||||
scrollTop: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText;
|
||||
LimitedText = text.substring(0, symbols);
|
||||
return LimitedText + "...";
|
||||
}
|
||||
return text;
|
||||
},
|
||||
generateSlug(text) {
|
||||
return slugify(text, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
locale: "ru",
|
||||
});
|
||||
},
|
||||
onScroll(e) {
|
||||
const windowTop = window.scrollY;
|
||||
this.scrollTop = windowTop > 100;
|
||||
|
||||
const headings = document.querySelectorAll("h2");
|
||||
const visor = document.querySelector("#visor");
|
||||
let lastVisibleHeading = null;
|
||||
|
||||
const visorRect = visor.getBoundingClientRect();
|
||||
|
||||
// Проверяем, находится ли визор в пределах видимости
|
||||
if (visorRect.top > window.scrollY) {
|
||||
this.currentNavSection = null;
|
||||
lastVisibleHeading = null; // Сбрасываем заголовок, если визор не виден
|
||||
return; // Выходим из функции, если визор не виден
|
||||
}
|
||||
|
||||
for (let i = 0; i < headings.length; i++) {
|
||||
const heading = headings[i];
|
||||
const rect = heading.getBoundingClientRect();
|
||||
|
||||
// Проверяем, находится ли заголовок в видимой области и касается ли он элемента visor
|
||||
if (
|
||||
rect.top >= 0 &&
|
||||
rect.bottom <= window.innerHeight &&
|
||||
rect.bottom >= visorRect.top &&
|
||||
rect.top <= visorRect.bottom
|
||||
) {
|
||||
// Проверяем, изменился ли заголовок
|
||||
if (heading !== lastVisibleHeading) {
|
||||
this.currentNavSection = heading.id;
|
||||
lastVisibleHeading = heading;
|
||||
}
|
||||
break; // Выходим из цикла, если нашли видимый заголовок
|
||||
}
|
||||
}
|
||||
},
|
||||
scrollToTop() {
|
||||
window.scrollTo(0, 0);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener("scroll", this.onScroll);
|
||||
},
|
||||
unmounted() {
|
||||
window.removeEventListener("scroll", this.onScroll);
|
||||
},
|
||||
props: {
|
||||
headerNavs: {
|
||||
type: Array,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
|
||||
<div class="sticky top-[100px] hidden h-[calc(100vh-121px)] max-w-[20%] min-w-[20%] md:flex md:shrink-0 md:flex-col md:justify-between">
|
||||
<nav v-if="subSectionPages"
|
||||
class="flex h-[calc(100vh-200px)] flex-col overflow-hidden pr-2 pb-4">
|
||||
<div class="text-gray-1000 mb-2 text-md font-medium">{{ currentSection }}</div>
|
||||
<div>
|
||||
<ul class="px-0.5 last-of-type:mb-0 mb-8">
|
||||
<li v-for="page in subSectionPages.data" :key="page.id" class="my-1.5 flex">
|
||||
<a :class="{'text-white font-normal bg-primaryBlue border': isSameRoute(page.path), 'text-gray-600 hover:text-[#2C6288]': !isSameRoute(page.path) }"
|
||||
:href="(page.is_url) ? page.path : route('page.view', page.path) + '/'"
|
||||
class="duration-300 flex gap-x-2 w-full rounded-md cursor-pointer items-center px-2 py-1.5 text-left text-sm">
|
||||
<BasicIcon class="w-4" :name="page.icon" />
|
||||
{{
|
||||
page.title
|
||||
}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
export default {
|
||||
name: "PageSubSectionLinks",
|
||||
components: {Link, BasicIcon},
|
||||
data() {
|
||||
return {
|
||||
currentNavSection: null,
|
||||
scrollTop: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isSameRoute(route) {
|
||||
if (this.$page.props.ziggy.location === this.$page.props.ziggy.url + '/' + route) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// console.log(IconsMap)
|
||||
|
||||
},
|
||||
|
||||
|
||||
|
||||
props: {
|
||||
subSectionPages: {
|
||||
type: Object,
|
||||
},
|
||||
currentSection: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div class="">
|
||||
<img @click="toggler = !toggler" class="shrink-0 w-full md:w-[200px] md:h-[300px] rounded-xl object-cover" :src="'/storage/' + photo" alt="Avatar">
|
||||
</div>
|
||||
|
||||
<FsLightbox class="" :toggler="toggler" :sources="[domainPath + '/storage/' + photo]"/>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import slugify from "slugify";
|
||||
import FsLightbox from "fslightbox-vue";
|
||||
|
||||
export default {
|
||||
name: "PersonAvatarBlock",
|
||||
components: { FsLightbox },
|
||||
data() {
|
||||
return {
|
||||
toggler: false,
|
||||
domainPath: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
generateSlug: function (text) {
|
||||
return slugify(text, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
locale: 'ru'
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.domainPath = window.location.origin;
|
||||
},
|
||||
props: {
|
||||
photo: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.fslightbox-container {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(breadcrumbs.mainSection, breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="$page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ personName }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="$page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ personName }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
|
||||
export default {
|
||||
name: "PersonBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
default: () => ({}), // Default to an empty object
|
||||
},
|
||||
personName: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,40 @@
|
||||
<!-- NavLink.vue -->
|
||||
<template>
|
||||
<a :class="linkClass"
|
||||
class="duration-150 block py-1 px-2 leading-[1.6] rounded-md"
|
||||
:href="href">
|
||||
{{ label }}
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PersonNavLink',
|
||||
props: {
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
href: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
linkClass() {
|
||||
return {
|
||||
'translate-x-2 text-[#135aae]': this.isActive,
|
||||
'bg-transperant text-gray-600 hover:text-gray-900': !this.isActive
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Добавьте стили, если это необходимо */
|
||||
</style>
|
||||
@@ -0,0 +1,126 @@
|
||||
<!-- NavLink.vue -->
|
||||
<template>
|
||||
<div class="flex items-center gap-x-10 gap-y-4 flex-wrap">
|
||||
<PersonAvatarBlock v-if="person.data.details.photo" :photo="person.data.details.photo" />
|
||||
<div class="grow">
|
||||
<h1 class="text-2xl font-medium text-gray-800 dark:text-neutral-200">
|
||||
{{ person.data.name }}
|
||||
</h1>
|
||||
<div class="">
|
||||
<template v-for="division_work in person.data.divisions_works">
|
||||
<Link :href="route('client.division.show', division_work.slug)" class="text-sm text-blue-500 dark:text-neutral-400 mr-2">
|
||||
{{ division_work.position }}
|
||||
</Link>
|
||||
</template>
|
||||
<template v-for="faculty_work in person.data.faculties_works">
|
||||
<Link :href="route('client.faculty.show', faculty_work.slug)" class="text-sm text-blue-500 dark:text-neutral-400 mr-2">
|
||||
{{ faculty_work.position }}
|
||||
</Link>
|
||||
</template>
|
||||
<template v-for="division_work in person.data.departments_work">
|
||||
<Link :href="route('client.department.show', { facultySlug: division_work.faculty_slug, departmentSlug: division_work.slug })" class="text-sm text-blue-500 dark:text-neutral-400 mr-2">
|
||||
{{ division_work.position }}
|
||||
</Link>
|
||||
</template>
|
||||
<template v-for="division_tech in person.data.departments_teach">
|
||||
<Link :href="route('client.department.show', { facultySlug: division_tech.faculty_slug, departmentSlug: division_tech.slug })" class="text-sm text-blue-500 dark:text-neutral-400 mr-2">
|
||||
{{ division_tech.position }}
|
||||
</Link>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<ul class="mt-5 flex flex-col gap-y-3">
|
||||
|
||||
<li v-if="person.data.details.contactPhone" class="flex items-center gap-x-2.5">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="shrink-0 size-3.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 6.75c0 8.284 6.716 15 15 15h2.25a2.25 2.25 0 0 0 2.25-2.25v-1.372c0-.516-.351-.966-.852-1.091l-4.423-1.106c-.44-.11-.902.055-1.173.417l-.97 1.293c-.282.376-.769.542-1.21.38a12.035 12.035 0 0 1-7.143-7.143c-.162-.441.004-.928.38-1.21l1.293-.97c.363-.271.527-.734.417-1.173L6.963 3.102a1.125 1.125 0 0 0-1.091-.852H4.5A2.25 2.25 0 0 0 2.25 4.5v2.25Z" />
|
||||
</svg>
|
||||
<a class="text-[13px] text-gray-500 underline hover:text-gray-800 hover:decoration-2 focus:outline-none focus:decoration-2 dark:text-neutral-500 dark:hover:text-neutral-400" href="#">
|
||||
{{ person.data.details.contactPhone }}
|
||||
</a>
|
||||
</li>
|
||||
<li v-if="person.data.details.contactEmail" class="flex items-center gap-x-2.5">
|
||||
<svg class="shrink-0 size-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect width="20" height="16" x="2" y="4" rx="2"></rect>
|
||||
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path>
|
||||
</svg>
|
||||
<a class="text-[13px] text-gray-500 underline hover:text-gray-800 hover:decoration-2 focus:outline-none focus:decoration-2 dark:text-neutral-500 dark:hover:text-neutral-400" href="#">
|
||||
{{ person.data.details.contactEmail }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5 sm:mt-7">
|
||||
<EducationBlock v-if="person.data.details.education.length > 0" title="Направление подготовки" :educations="person.data.details.education" />
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<ListBlock v-if="person.data.details.awards.length > 0" name-list="Награды" :list="person.data.details.awards" />
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<ListBlock v-if="person.data.details.professionalRetraining.length > 0" name-list="Профессиональная переподготовка" :list="person.data.details.professionalRetraining" />
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<ListBlock v-if="person.data.details.professionalDevelopment.length > 0" name-list="Повышение квалификации" :list="person.data.details.professionalDevelopment" />
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<ListBlock v-if="person.data.details.professDisciplines.length > 0" name-list="Преподаваемые дисциплины" :list="person.data.details.professDisciplines" />
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<WorkExperienceBlock v-if="person.data.details.workExperience.total" title="Стаж" :work-exp-by-prof="person.data.details.workExperience.byProf" :work-exp-total="person.data.details.workExperience.total" />
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<ListBlock v-if="person.data.details.attendedConferences.length > 0" name-list="Участие в конференциях" :list="person.data.details.attendedConferences" />
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<PublicationBlock v-if="person.data.details.publications.length > 0" name-list="Публикации" :list="person.data.details.publications" />
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<OtherBlock v-if="person.data.details.other?.length > 0" name-list="Другое" :blocks="person.data.details.other" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import OtherBlock from "@/componentss/features/persons/components/sections/blocks/OtherBlock.vue";
|
||||
import EducationBlock from "@/componentss/features/persons/components/sections/blocks/EducationBlock.vue";
|
||||
import ListBlock from "@/componentss/features/persons/components/sections/blocks/ListBlock.vue";
|
||||
import PersonAvatarBlock from "@/componentss/features/persons/components/PersonAvatarBlock.vue";
|
||||
import WorkExperienceBlock from "@/componentss/features/persons/components/sections/blocks/WorkExperienceBlock.vue";
|
||||
import PublicationBlock from "@/componentss/features/persons/components/sections/blocks/PublicationBlock.vue";
|
||||
|
||||
|
||||
export default {
|
||||
name: 'InfoSection',
|
||||
components: {OtherBlock, EducationBlock, ListBlock, PersonAvatarBlock, Link, WorkExperienceBlock, PublicationBlock},
|
||||
props: {
|
||||
person: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
linkClass() {
|
||||
return {
|
||||
'translate-x-2 text-[#135aae]': this.isActive,
|
||||
'bg-transperant text-gray-600 hover:text-gray-900': !this.isActive
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Добавьте стили, если это необходимо */
|
||||
</style>
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
<!-- NavLink.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<h2 :id="generateSlug(title)" class="mb-3 font-medium text-gray-800 dark:text-neutral-200">
|
||||
{{ title }}
|
||||
</h2>
|
||||
|
||||
<template v-for="education in educations">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-1 my-4">
|
||||
<div class="p-4 border border-gray-200 rounded-lg dark:border-neutral-700">
|
||||
<h3 class="mb-1 text-xs text-gray-600 dark:text-neutral-400">
|
||||
{{ education.year }}
|
||||
</h3>
|
||||
|
||||
<p class="font-semibold text-sm text-gray-800 dark:text-neutral-200">
|
||||
{{ education.content }}
|
||||
</p>
|
||||
|
||||
<p class="mt-1 text-sm text-gray-600 dark:text-neutral-400">
|
||||
{{ education.institution }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: 'EducationBlock',
|
||||
props: {
|
||||
educations: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
generateSlug(text) {
|
||||
return slugify(text, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
locale: "ru",
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Добавьте стили, если это необходимо */
|
||||
</style>
|
||||
@@ -0,0 +1,46 @@
|
||||
<!-- NavLink.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<h2 :id="generateSlug(nameList)" class="mb-3 font-medium text-gray-800 dark:text-neutral-200">
|
||||
{{ nameList }}
|
||||
</h2>
|
||||
<ul class="list-disc ms-6 mt-3 space-y-1.5">
|
||||
<template v-for="el in list">
|
||||
<li class="ps-1 text-sm text-gray-600 dark:text-neutral-400">
|
||||
{{ el.item }}
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: 'ListBlock',
|
||||
props: {
|
||||
list: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
nameList: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
generateSlug(text) {
|
||||
return slugify(text, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
locale: "ru",
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Добавьте стили, если это необходимо */
|
||||
</style>
|
||||
@@ -0,0 +1,42 @@
|
||||
<!-- NavLink.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<h2 :id="generateSlug(nameList)" class="mb-3 font-medium text-gray-800 dark:text-neutral-200">
|
||||
{{ nameList }}
|
||||
</h2>
|
||||
<Builder :blocks="blocks" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import slugify from "slugify";
|
||||
import Builder from "@/componentss/shared/builder/pageBuilder/Builder.vue";
|
||||
|
||||
export default {
|
||||
name: 'OtherBlock',
|
||||
components: {Builder},
|
||||
props: {
|
||||
blocks: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
nameList: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
generateSlug(text) {
|
||||
return slugify(text, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
locale: "ru",
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Добавьте стили, если это необходимо */
|
||||
</style>
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<!-- NavLink.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<template v-for="el in list">
|
||||
<h2 :id="generateSlug(el.category_publication)" class="my-4 font-medium text-gray-800">{{ el.category_publication }}</h2>
|
||||
<ul class="list-disc ms-6 mt-3 space-y-1.5">
|
||||
<template v-for="el in el.publication">
|
||||
<li class="ps-1 text-sm text-gray-600 dark:text-neutral-400">
|
||||
{{ el.item }}
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: 'PublicationBlock',
|
||||
props: {
|
||||
list: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
nameList: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
generateSlug(text) {
|
||||
return slugify(text, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
locale: "ru",
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Добавьте стили, если это необходимо */
|
||||
</style>
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<!-- NavLink.vue -->
|
||||
<template>
|
||||
<h2 :id="generateSlug(title)" class="mb-3 font-medium text-gray-800 dark:text-neutral-200">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-1 gap-3">
|
||||
<p class="mt-1 text-sm text-gray-600 dark:text-neutral-400">
|
||||
Стаж работы: {{ workExpTotal }}
|
||||
</p>
|
||||
<p class="mt-1 text-sm text-gray-600 dark:text-neutral-400">
|
||||
Стаж по специальности: {{ workExpByProf }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: 'WorkExperienceBlock',
|
||||
props: {
|
||||
workExpTotal: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
workExpByProf: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
generateSlug(text) {
|
||||
return slugify(text, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
locale: "ru",
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Добавьте стили, если это необходимо */
|
||||
</style>
|
||||
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
|
||||
<div class="col-start-2">
|
||||
<div class="hs-tooltip inline-block">
|
||||
<button type="button" class="hs-tooltip-toggle underline hover:text-blue-400 duration-300">
|
||||
Над статьей работали
|
||||
<span class="hs-tooltip-content hs-tooltip-shown:opacity-100 hs-tooltip-shown:visible opacity-0 transition-opacity inline-block absolute duration-300 invisible z-10 py-1 px-2 bg-gray-900 text-xs font-medium text-white rounded shadow-sm dark:bg-neutral-700" role="tooltip">
|
||||
<template v-for="author in authors">
|
||||
{{ author }} <br>
|
||||
</template>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: "PostAuthorsList",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
authors: {
|
||||
type: Array,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
|
||||
<div v-if="images.length" class="grid gap-4 border-t border-gray-300 py-4">
|
||||
<div class="relative">
|
||||
<img loading="lazy"
|
||||
class="filter brightness-[0.8] w-full max-h-[500px] object-cover rounded-lg hover:opacity-95 hover:duration-200 transition"
|
||||
:src="'/storage/' + images[0]" data-hs-overlay="#modal-post-gallery" alt="">
|
||||
<div class="absolute inset-x-0 bottom-5 flex flex-col justify-center items-center">
|
||||
<p class="text-white text-sm lg:text-xl text-center">{{ title }}</p>
|
||||
<span class="text-gray-300 text-sm">{{ images.length }} фотографий</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-post-gallery" class="hs-overlay hidden size-full fixed top-0 start-0 z-[80] overflow-x-hidden overflow-y-auto pointer-events-none" role="dialog" tabindex="-1" aria-labelledby="modal-post-gallery-label">
|
||||
<div class="hs-overlay-open:mt-0 hs-overlay-open:opacity-100 hs-overlay-open:duration-500 mt-10 opacity-0 transition-all max-w-full max-h-full h-full">
|
||||
<div class="flex flex-col bg-white pointer-events-auto max-w-full max-h-full h-full dark:bg-neutral-800">
|
||||
<div class="flex justify-between items-center py-3 px-4 border-b dark:border-neutral-700">
|
||||
<h3 id="modal-post-gallery-label" class="font-bold text-gray-800 dark:text-white">
|
||||
Галлерея: {{ title }}
|
||||
</h3>
|
||||
<button type="button" class="size-8 inline-flex justify-center items-center gap-x-2 rounded-full border border-transparent bg-gray-100 text-gray-800 hover:bg-gray-200 focus:outline-none focus:bg-gray-200 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-700 dark:hover:bg-neutral-600 dark:text-neutral-400 dark:focus:bg-neutral-600" aria-label="Close" data-hs-overlay="#modal-post-gallery">
|
||||
<span class="sr-only">Close</span>
|
||||
<svg class="shrink-0 size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 6 6 18"></path>
|
||||
<path d="m6 6 12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<div class="grid grid-cols-2 sm:grid-cols-5 gap-3">
|
||||
<div v-for="(image, index) in images" class="group block relative overflow-hidden rounded-lg">
|
||||
<img loading="lazy" @click="openLightboxOnSlide(index + 1)" class="w-full size-40 object-cover bg-gray-100 rounded-lg" :src="'/storage/' + image">
|
||||
<div class="absolute bottom-1 end-1 opacity-0 group-hover:opacity-100 transition">
|
||||
<div class="flex items-center gap-x-1 py-1 px-2 bg-white border border-gray-200 text-gray-800 rounded-lg">
|
||||
<svg class="shrink-0 size-3" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<span class="text-xs">Открыть</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<FsLightbox class="" :slide="slide" :toggler="toggler" :sources="images.map(image => domainPath + '/storage/' + image)"/>
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import FsLightbox from "fslightbox-vue";
|
||||
export default {
|
||||
name: "PostGallery",
|
||||
components: {Link, FsLightbox},
|
||||
data() {
|
||||
return {
|
||||
toggler: false,
|
||||
slide: 1,
|
||||
domainPath: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
openLightboxOnSlide: function(number) {
|
||||
this.slide = number;
|
||||
this.toggler = !this.toggler;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.domainPath = window.location.origin;
|
||||
},
|
||||
|
||||
props: {
|
||||
images: {
|
||||
type: Array,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,209 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(breadcrumbs.mainSection, breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.post.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Новости', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="$page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(postTitle, 60) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.post.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
{{ textLimit('Новости', 30) }}
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="$page.props.ziggy.location" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
{{ textLimit(postTitle, 60) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
export default {
|
||||
name: "PostItemBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.innerWidth < 1024; // Проверка на мобильные устройства
|
||||
}
|
||||
return false; // По умолчанию возвращаем false, когда не в браузере
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
default: () => ({}), // Default to an empty object
|
||||
},
|
||||
postTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<component
|
||||
v-for="(filter, index) in filters"
|
||||
:key="index"
|
||||
:is="getComponent(filter.type)"
|
||||
:filter="filter"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import SearchBadge from "@/componentss/shared/badge/badges/SearchBadge.vue";
|
||||
import CategoryBadge from "@/componentss/shared/badge/badges/CategoryBadge.vue";
|
||||
import TagBadge from "@/componentss/shared/badge/badges/TagBadge.vue";
|
||||
export default {
|
||||
name: "PostListBadge",
|
||||
components: {
|
||||
Link,
|
||||
SearchBadge,
|
||||
CategoryBadge,
|
||||
TagBadge,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getComponent(type) {
|
||||
const componentMap = {
|
||||
search: 'SearchBadge',
|
||||
category: 'CategoryBadge',
|
||||
tag: 'TagBadge',
|
||||
};
|
||||
return componentMap[type] || null;
|
||||
},
|
||||
},
|
||||
props: {
|
||||
filters: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<div class="flex justify-between pb-4 items-center">
|
||||
<div class="flex w-full sm:items-center gap-x-5 sm:gap-x-3">
|
||||
<div class="grow">
|
||||
<div class="grid sm:flex sm:justify-between sm:items-center gap-2">
|
||||
<BreadcrumbsWrapper v-if="breadcrumbs">
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.mainSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSectionClick(breadcrumbs.mainSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(breadcrumbs.mainSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="breadcrumbs.subSection" class="text-sm">
|
||||
<span class="flex items-center text-gray-500 hover:text-primaryBlue cursor-pointer" @click.prevent="handleSubSectionClick(breadcrumbs.mainSection, breadcrumbs.subSection)">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit(breadcrumbs.subSection.data.title, 25) }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.post.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Новости', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
<BreadcrumbsWrapper v-else>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('index')" class="flex items-center text-gray-500 hover:text-blue-600" href="/">
|
||||
<BasicIcon class="size-5" name="home" />
|
||||
</Link>
|
||||
</li>
|
||||
<li class="text-sm">
|
||||
<Link :href="route('client.post.index')" class="flex items-center text-gray-500 hover:text-blue-600">
|
||||
<svg class="flex-shrink-0 mx-2 overflow-visible h-2.5 w-2.5 text-gray-400"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1L10.6869 7.16086C10.8637 7.35239 10.8637 7.64761 10.6869 7.83914L5 14"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ textLimit('Новости', 30) }}
|
||||
</Link>
|
||||
</li>
|
||||
</BreadcrumbsWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import BreadcrumbsWrapper from "@/componentss/ui/wrappers/BreadcrumbsWrapper.vue";
|
||||
export default {
|
||||
name: "PostListBreadcrumbs",
|
||||
components: {BreadcrumbsWrapper, BasicIcon, Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
isMobileDevice() {
|
||||
return window.innerWidth < 1024; // Задайте порог для мобильных устройств
|
||||
},
|
||||
handleSectionClick(breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSection(breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSection(breadcrumb)
|
||||
}
|
||||
},
|
||||
handleSubSectionClick(mainSectionBreadcrumb, breadcrumb) {
|
||||
if (this.isMobileDevice()) {
|
||||
this.toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
} else {
|
||||
this.toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb)
|
||||
}
|
||||
},
|
||||
highlightNavItem(item) {
|
||||
item.classList.add('animate-pulse');
|
||||
|
||||
setTimeout(() => {
|
||||
item.classList.remove('animate-pulse');
|
||||
}, 4000);
|
||||
},
|
||||
openMobileNavMenu() {
|
||||
const openMobileNavBtn = document.getElementById('open-mobile-btn');
|
||||
openMobileNavBtn.click();
|
||||
},
|
||||
toggleMobileNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
this.openMobileNavMenu()
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + mainSectionBreadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
if (!sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
const subSectionNavBlock = mobileNavElement.querySelector('#nav-sub-section-accordion-' + breadcrumb.data.slug);
|
||||
const subSectionNavBlockBtn = mobileNavElement.querySelector('#nav-sub-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (subSectionNavBlock.classList.contains('active')) {
|
||||
subSectionNavBlockBtn.click()
|
||||
}
|
||||
|
||||
this.highlightNavItem(subSectionNavBlock)
|
||||
},
|
||||
toggleMobileNavSection(breadcrumb) {
|
||||
const mobileNavElement = document.getElementById('open-mobile-nav');
|
||||
const sectionNavBlock = mobileNavElement.querySelector('#nav-section-accordion-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = mobileNavElement.querySelector('#nav-section-accordion-btn-' + breadcrumb.data.slug);
|
||||
if (sectionNavBlock.classList.contains('active')) {
|
||||
sectionNavBlockBtn.click()
|
||||
}
|
||||
this.openMobileNavMenu()
|
||||
|
||||
this.highlightNavItem(sectionNavBlock)
|
||||
|
||||
},
|
||||
toggleDesktopNavSubSection(mainSectionBreadcrumb, breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavTitle = desktopNavElement.querySelector('#nav-sub-section-title-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + mainSectionBreadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
this.highlightNavItem(sectionNavTitle)
|
||||
},
|
||||
toggleDesktopNavSection(breadcrumb) {
|
||||
const desktopNavElement = document.getElementById('desktop-nav');
|
||||
const sectionNavBlock = desktopNavElement.querySelector('#nav-section-menu-' + breadcrumb.data.slug);
|
||||
const sectionNavBlockBtn = desktopNavElement.querySelector('#nav-section-btn-' + breadcrumb.data.slug);
|
||||
sectionNavBlockBtn.click()
|
||||
// this.highlightNavItem(sectionNavBlock)
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
props: {
|
||||
breadcrumbs: {
|
||||
type: Object,
|
||||
},
|
||||
postTitle: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
|
||||
<div class="sm:col-span-2 md:grow">
|
||||
<!--Фильтр-->
|
||||
|
||||
<button type="button" class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none" aria-haspopup="dialog" aria-expanded="false" aria-controls="hs-offcanvas-example" data-hs-overlay="#hs-offcanvas-example">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 6h9.75M10.5 6a1.5 1.5 0 1 1-3 0m3 0a1.5 1.5 0 1 0-3 0M3.75 6H7.5m3 12h9.75m-9.75 0a1.5 1.5 0 0 1-3 0m3 0a1.5 1.5 0 0 0-3 0m-3.75 0H7.5m9-6h3.75m-3.75 0a1.5 1.5 0 0 1-3 0m3 0a1.5 1.5 0 0 0-3 0m-9.75 0h9.75" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
|
||||
<!--Конец Фильтра-->
|
||||
</div>
|
||||
<div id="hs-offcanvas-example" class="hs-overlay hs-overlay-open:translate-x-0 hidden -translate-x-full fixed top-0 start-0 transition-all duration-300 transform h-full max-w-xs w-full z-[80] bg-white border-e overflow-auto" role="dialog" tabindex="-1" aria-labelledby="hs-offcanvas-example-label">
|
||||
<div class="flex justify-between items-center py-3 px-4 border-b">
|
||||
<h3 id="hs-offcanvas-example-label" class="font-bold text-gray-800">
|
||||
Фильтры
|
||||
</h3>
|
||||
<button type="button" class="size-8 inline-flex justify-center items-center gap-x-2 rounded-full border border-transparent bg-gray-100 text-gray-800 hover:bg-gray-200 focus:outline-none focus:bg-gray-200 disabled:opacity-50 disabled:pointer-events-none" aria-label="Close" data-hs-overlay="#hs-offcanvas-example">
|
||||
<span class="sr-only">Close</span>
|
||||
<svg class="shrink-0 size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 6 6 18"></path>
|
||||
<path d="m6 6 12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<SortingByFilter :sortingBy_filter="sortingBy_filter" />
|
||||
<div class="hs-accordion-group">
|
||||
<div class="hs-accordion" :id="'id' + category_filter.type">
|
||||
<button class="hs-accordion-toggle hs-accordion-active:text-blue-600 py-3 inline-flex items-center gap-x-3 w-full font-semibold text-start text-gray-800 hover:text-gray-500 focus:outline-none focus:text-gray-500 rounded-lg disabled:opacity-50 disabled:pointer-events-none" aria-expanded="false" aria-controls="hs-basic-with-arrow-collapse-two">
|
||||
<svg class="hs-accordion-active:hidden block size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m6 9 6 6 6-6"></path>
|
||||
</svg>
|
||||
<svg class="hs-accordion-active:block hidden size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m18 15-6-6-6 6"></path>
|
||||
</svg>
|
||||
Категории
|
||||
<span v-if="category_filter.value" class="inline-flex items-center gap-x-1.5 py-1.5 px-3 rounded-md text-xs font-medium border border-gray-200 bg-white text-gray-800 shadow-sm dark:bg-neutral-900 dark:border-neutral-700 dark:text-white">{{ category_filter.value.length }}</span>
|
||||
|
||||
</button>
|
||||
<div id="hs-basic-with-arrow-collapse-two" class="hs-accordion-content hidden w-full overflow-hidden transition-[height] duration-300" role="region" :aria-labelledby="'id' + tag_filter.type">
|
||||
<CategoryFilter :categories="items" :category_filter="category_filter" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
export default {
|
||||
name: "PostListFilter",
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
items: {
|
||||
type: Object,
|
||||
},
|
||||
category_filter: {
|
||||
type: Object,
|
||||
},
|
||||
sortingBy_filter: {
|
||||
type: Object,
|
||||
},
|
||||
tag_filter: {
|
||||
type: Object,
|
||||
},
|
||||
tags: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div class="group cursor-pointer">
|
||||
<div
|
||||
class="overflow-hidden rounded-md max-h-[250px] bg-gray-100 transition-all hover:scale-105 dark:bg-gray-800"
|
||||
>
|
||||
<a
|
||||
class="relative block aspect-square"
|
||||
:href="route('client.post.show', post.slug)"
|
||||
><img
|
||||
alt="Thumbnail"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-nimg="fill"
|
||||
class="object-cover transition-all"
|
||||
style="
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
inset: 0px;
|
||||
color: transparent;
|
||||
"
|
||||
sizes="(max-width: 768px) 30vw, 33vw"
|
||||
:src="post.preview ? '/storage/' + post.preview : '/img/thumbnail-1.png'"
|
||||
/></a>
|
||||
</div>
|
||||
<div class="">
|
||||
<div>
|
||||
<div v-if="post.category" class="flex gap-3">
|
||||
<a :href="route('client.post.index', { 'category[]': post.category.slug })">
|
||||
<span class="inline-block text-xs font-medium tracking-wider uppercase mt-5 text-blue-600">
|
||||
{{ post.category ? post.category.title : "Новости" }}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div v-else class="flex gap-3">
|
||||
<span>
|
||||
<span class="inline-block text-xs font-medium tracking-wider uppercase mt-5 text-blue-600">
|
||||
Новости
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<h2
|
||||
class="text-lg font-semibold leading-snug tracking-tight mt-2 dark:text-white"
|
||||
>
|
||||
<a :href="route('client.post.show', post.slug)"
|
||||
><span class="duration-200 group-hover:text-gray-500">{{
|
||||
post.title
|
||||
}}</span></a
|
||||
>
|
||||
</h2>
|
||||
<div class="">
|
||||
<p
|
||||
class="mt-2 line-clamp-3 text-sm text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
<a
|
||||
:href="route('client.post.show', post.slug)"
|
||||
>{{ post.preview_text }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="mt-3 flex items-center space-x-3 text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
<span>
|
||||
<div class="flex items-center gap-3">
|
||||
<span v-if="post && post.authors && post.authors.length > 0" class="truncate text-sm">
|
||||
{{ textLimit(post.authors[0], 20) }}
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
<span class="text-xs text-gray-300 dark:text-gray-600"
|
||||
>•</span
|
||||
>
|
||||
<span class="truncate text-sm">{{ post.created_post }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "PostListItem",
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText;
|
||||
LimitedText = text.substring(0, symbols);
|
||||
return LimitedText + "...";
|
||||
}
|
||||
return text;
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
post: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="sm:col-span-1 w-full">
|
||||
<label for="hs-as-table-product-review-search" class="sr-only">Поиск</label>
|
||||
<div class="relative">
|
||||
<input autocomplete="off" @input="search" v-model="searchInput" type="text"
|
||||
id="hs-as-table-product-review-search"
|
||||
name="hs-as-table-product-review-search"
|
||||
class="py-3 px-3 pl-11 block flex-1 w-full border-gray-200 shadow-sm rounded-md text-sm focus:z-10 focus:border-blue-500 focus:ring-blue-500 dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
|
||||
placeholder="Поиск новостей">
|
||||
<div
|
||||
class="absolute inset-y-0 left-0 flex items-center pointer-events-none pl-4">
|
||||
<svg class="h-4 w-4 text-gray-400" xmlns="http://www.w3.org/2000/svg"
|
||||
width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path
|
||||
d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { debounce } from "lodash";
|
||||
|
||||
export default {
|
||||
name: "PostListSearch",
|
||||
data() {
|
||||
return {
|
||||
searchInput: this.search_filter.value,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
search: debounce(function () {
|
||||
if(this.searchInput === "") {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('search');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl,{
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
replace: true,
|
||||
});
|
||||
} else {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('page');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl,{
|
||||
method: 'get',
|
||||
data: {
|
||||
search: this.searchInput,
|
||||
},
|
||||
preserveState: true,
|
||||
replace: true,
|
||||
})
|
||||
}
|
||||
}, 500),
|
||||
|
||||
},
|
||||
props: [
|
||||
'search_filter'
|
||||
],
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
|
||||
<span class="block">Чтение займет {{ time }}<!-- --> Минуты</span>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: "PostTimeRead",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
time: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div class="min-w-[12rem] py-1 space-y-3">
|
||||
<button @click.prevent="clearFilter" class="text-gray-500 text-sm flex gap-x-1 items-center hover:text-gray-700">
|
||||
<BasicIcon class="w-4 h-4" name="delete" />
|
||||
<span>Очистить</span>
|
||||
</button>
|
||||
|
||||
<div class="divide-y divide-gray-200 dark:divide-gray-700 max-h-[30vh] overflow-y-auto">
|
||||
<div>
|
||||
<div class="flex flex-col ml-3">
|
||||
<div v-for="(form, index) in forms">
|
||||
<input v-model="formEdu" :value="index" @change="filter"
|
||||
type="radio" class="shrink-0 mt-0.5 border-gray-200 rounded-full text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none"
|
||||
:id="'inp-tag' + index">
|
||||
<label :for="'inp-tag' + index" class="text-sm text-gray-500 ms-3 dark:text-neutral-400">{{ form }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
import {debounce} from "lodash";
|
||||
export default {
|
||||
name: "FormEducationalFilter",
|
||||
components: {
|
||||
BasicIcon,
|
||||
Link,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formEdu: this.formEdu_filter.value || [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
filter: debounce(function () {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('page');
|
||||
url.searchParams.delete('form');
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
data: {
|
||||
form: this.formEdu,
|
||||
},
|
||||
});
|
||||
}, 500),
|
||||
clearFilter() {
|
||||
let url = new URL(window.location.href);
|
||||
url.searchParams.delete('form');
|
||||
this.formEdu = [];
|
||||
this.searchTerm = ''; // Сбросить поле поиска
|
||||
let newUrl = url.toString();
|
||||
this.$inertia.visit(newUrl, {
|
||||
method: 'get',
|
||||
preserveState: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
props: {
|
||||
forms: {
|
||||
type: Object,
|
||||
},
|
||||
formEdu_filter: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<!--Фильтр-->
|
||||
<button type="button"
|
||||
aria-haspopup="dialog" aria-expanded="false" aria-controls="hs-offcanvas-example" data-hs-overlay="#hs-offcanvas-example"
|
||||
class="flex w-full py-2 px-4 items-center gap-x-2 text-xs font-medium rounded-lg border border-gray-200 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-primaryBlue focus:text-white disabled:opacity-50 disabled:pointer-events-none">
|
||||
<BasicIcon class="shrink-0 size-4" name="settings" />
|
||||
<span>Фильтры</span>
|
||||
</button>
|
||||
|
||||
|
||||
<!--Конец Фильтра-->
|
||||
<div id="hs-offcanvas-example" class="hs-overlay hs-overlay-open:translate-x-0 hidden -translate-x-full fixed top-0 start-0 transition-all duration-300 transform h-full max-w-xs w-full z-[80] bg-white border-e overflow-auto" role="dialog" tabindex="-1" aria-labelledby="hs-offcanvas-example-label">
|
||||
<div class="flex justify-between items-center py-3 px-4 border-b">
|
||||
<h3 id="hs-offcanvas-example-label" class="font-bold text-gray-800">
|
||||
Фильтры
|
||||
</h3>
|
||||
<button type="button" class="size-8 inline-flex justify-center items-center gap-x-2 rounded-full border border-transparent bg-gray-100 text-gray-800 hover:bg-gray-200 focus:outline-none focus:bg-gray-200 disabled:opacity-50 disabled:pointer-events-none" aria-label="Close" data-hs-overlay="#hs-offcanvas-example">
|
||||
<span class="sr-only">Close</span>
|
||||
<svg class="shrink-0 size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 6 6 18"></path>
|
||||
<path d="m6 6 12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="hs-accordion-group">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BasicIcon from "@/componentss/ui/icons/BasicIcon.vue";
|
||||
|
||||
export default {
|
||||
name: "ScheduleListFilter",
|
||||
components: {BasicIcon},
|
||||
|
||||
|
||||
props: {
|
||||
faculty_filter: {
|
||||
type: Object,
|
||||
},
|
||||
formEdu_filter: {
|
||||
type: Object
|
||||
},
|
||||
forms_educational: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<h1 class="text-2xl sm:text-4xl font-bold text-gray-800 text-center">
|
||||
{{ header }}
|
||||
</h1>
|
||||
<p class="mt-3 text-gray-600 text-center">
|
||||
{{ bottomText }}
|
||||
</p>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import slugify from "slugify";
|
||||
|
||||
export default {
|
||||
name: "ScheduleListTitle",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
header: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
bottomText: {
|
||||
type: String,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div class="relative px-3 pt-3 flex justify-start items-center overflow-x-auto whitespace-nowrap hide-scrollbar">
|
||||
<button @click="categorySort(null)" :class="selectedCategory === null ? 'bg-blue-50 text-blue-500 border-blue-300' : ''" class="hover:bg-gray-50 duration-150 border border-[#EAEAEA] rounded font-light text-[13px] px-1 mr-2" type="button">Все</button>
|
||||
<template v-for="category in categories">
|
||||
<button @click="categorySort(category)"
|
||||
:class="{
|
||||
'bg-blue-50': selectedCategory === category,
|
||||
'text-blue-500': selectedCategory === category,
|
||||
'border-blue-300': selectedCategory === category,
|
||||
}"
|
||||
class="hover:bg-gray-50 duration-150 border border-[#EAEAEA] rounded font-light text-[13px] px-1 mr-2" type="button">{{ category }}</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {debounce} from "lodash";
|
||||
|
||||
export default {
|
||||
name: "CategorySearchList",
|
||||
data() {
|
||||
return {
|
||||
selectedCategory: null,
|
||||
categories: null,
|
||||
paginate: null,
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
categorySort: debounce(function (category) {
|
||||
this.loading = true
|
||||
this.selectedCategory = category; // Устанавливаем выбранную категорию
|
||||
this.$emit('update:selected-category', this.selectedCategory, this.categories, this.paginate); // Эмитируем событие
|
||||
axios({
|
||||
method: "get",
|
||||
url: route('client.search.index'),
|
||||
params: {
|
||||
search: this.search.toLowerCase(),
|
||||
category: category
|
||||
}
|
||||
}).then((response) => {
|
||||
this.paginate = response.data.paginate;
|
||||
this.result = response.data.searchRes;
|
||||
this.categories = response.data.result_type;
|
||||
this.loading = false;
|
||||
});
|
||||
}, 500),
|
||||
},
|
||||
props: {
|
||||
categories: {
|
||||
type: Array,
|
||||
},
|
||||
search: {
|
||||
type: String,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,184 @@
|
||||
<template>
|
||||
<div class="border-b">
|
||||
<div v-if="result !== null && result.length !== 0" class="relative px-3 pt-3 flex justify-start items-center overflow-x-auto whitespace-nowrap hide-scrollbar">
|
||||
<button @click="categorySort(null)"
|
||||
:class="{
|
||||
'bg-blue-50': selectedCategory === null,
|
||||
'text-blue-500': selectedCategory === null,
|
||||
'border-blue-300': selectedCategory === null,
|
||||
'animate-pulse': loading === true
|
||||
}"
|
||||
class="hover:bg-gray-50 duration-150 border border-[#EAEAEA] rounded font-light text-[13px] px-1 mr-2" type="button">Все</button>
|
||||
<template v-for="category in categories">
|
||||
<button @click="categorySort(category)"
|
||||
:class="{
|
||||
'bg-blue-50': selectedCategory === category,
|
||||
'text-blue-500': selectedCategory === category,
|
||||
'border-blue-300': selectedCategory === category,
|
||||
'animate-pulse': loading === true
|
||||
}"
|
||||
class="hover:bg-gray-50 duration-150 border border-[#EAEAEA] rounded font-light text-[13px] px-1 mr-2" type="button">
|
||||
{{ruCategories()[category] }}
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
<div class="relative px-1 py-2 flex justify-between items-center">
|
||||
<input autofocus="autofocus" autocomplete="off" @input="search" v-model="searchInput" type="text"
|
||||
id="hs-as-table-product-review-search"
|
||||
name="hs-as-table-product-review-search"
|
||||
class="py-1 placeholder-[#8F8F8F] font-light px-2 block flex-1 w-full border-none text-lg focus:z-10 border-transparent focus:border-transparent focus:ring-0"
|
||||
placeholder="Поиск по сайту">
|
||||
<button :data-hs-overlay="'#' + open_id" class="hover:bg-gray-50 duration-150 border border-[#EAEAEA] rounded font-light text-[13px] px-1 mr-4" type="button">Esc</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-y-auto relative">
|
||||
<ResultList :result="result" :loading="loading" :selected-category="selectedCategory" />
|
||||
</div>
|
||||
<nav v-if="paginate" class="bg-white border border-gray-100 flex items-center gap-x-1 fixed bottom-4 w-[200px] justify-center left-0 right-0 mx-auto py-2 rounded-xl " aria-label="Pagination">
|
||||
<button @click="prev(paginate.prev_page)" :disabled="!paginate.prev_page" type="button" class="min-h-[38px] min-w-[38px] py-2 px-2.5 inline-flex justify-center items-center gap-x-2 text-sm rounded-lg text-gray-800 hover:bg-gray-100 focus:outline-none disabled:opacity-50 disabled:pointer-events-none" aria-label="Previous">
|
||||
<svg class="shrink-0 size-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m15 18-6-6 6-6"></path>
|
||||
</svg>
|
||||
<span class="sr-only">Previous</span>
|
||||
</button>
|
||||
<div class="flex items-center gap-x-1">
|
||||
<span class="min-h-[38px] min-w-[38px] flex justify-center items-center border border-gray-200 text-gray-800 py-2 px-3 text-sm rounded-lg focus:outline-none focus:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none">{{ paginate.current_page }}</span>
|
||||
<span class="min-h-[38px] flex justify-center items-center text-gray-500 py-2 px-1.5 text-sm">из</span>
|
||||
<span class="min-h-[38px] flex justify-center items-center text-gray-500 py-2 px-1.5 text-sm">{{ paginate.last_page }}</span>
|
||||
</div>
|
||||
<button @click="next(paginate.next_page)" :disabled="!paginate.next_page" type="button" class="min-h-[38px] min-w-[38px] py-2 px-2.5 inline-flex justify-center items-center gap-x-2 text-sm rounded-lg text-gray-800 hover:bg-gray-100 focus:outline-none disabled:opacity-50 disabled:pointer-events-none" aria-label="Next">
|
||||
<span class="sr-only">Next</span>
|
||||
<svg class="shrink-0 size-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m9 18 6-6-6-6"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {debounce} from "lodash";
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import {ruCategories} from "@/assets/data/ruCategories.js";
|
||||
import ResultList from "@/componentss/features/search/components/ResultList.vue";
|
||||
export default {
|
||||
name: "GlobalSearch",
|
||||
data() {
|
||||
return {
|
||||
searchInput: "",
|
||||
result: null,
|
||||
paginate: null,
|
||||
selectedCategory: null,
|
||||
categories: null,
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ResultList,
|
||||
Link,
|
||||
},
|
||||
methods: {
|
||||
ruCategories() {
|
||||
return ruCategories
|
||||
},
|
||||
categorySort: debounce(function(category) {
|
||||
this.toggleLoadingState(true);
|
||||
axios({
|
||||
method: "get",
|
||||
url: route('client.search.index'),
|
||||
params: {
|
||||
search: this.searchInput.toLowerCase(),
|
||||
category: category
|
||||
}
|
||||
}).then((response) => {
|
||||
this.paginate = response.data.paginate;
|
||||
this.result = response.data.searchRes;
|
||||
this.categories = response.data.result_type;
|
||||
this.selectedCategory = response.data.selectedCategory;
|
||||
this.toggleLoadingState(false);
|
||||
}).catch((error) => {
|
||||
console.error("Ошибка при получении данных:", error);
|
||||
this.toggleLoadingState(false);
|
||||
});
|
||||
}, 500),
|
||||
search: debounce(function () {
|
||||
axios({
|
||||
method: "get",
|
||||
url: route('client.search.index'),
|
||||
params: {
|
||||
search: this.searchInput.toLowerCase(),
|
||||
}
|
||||
}).then((response) => {
|
||||
this.paginate = response.data.paginate
|
||||
this.result = response.data.searchRes;
|
||||
this.categories = response.data.result_type
|
||||
});
|
||||
}, 500),
|
||||
|
||||
next: debounce(function (page) {
|
||||
this.toggleLoadingState(true);
|
||||
axios({
|
||||
method: "get",
|
||||
url: route('client.search.index'),
|
||||
params: {
|
||||
search: this.searchInput.toLowerCase(),
|
||||
page: page,
|
||||
category: this.selectedCategory
|
||||
}
|
||||
}).then((response) => {
|
||||
this.paginate = response.data.paginate
|
||||
this.result = response.data.searchRes;
|
||||
this.toggleLoadingState(false);
|
||||
|
||||
});
|
||||
}, 500),
|
||||
|
||||
prev: debounce(function (page) {
|
||||
this.toggleLoadingState(true);
|
||||
axios({
|
||||
method: "get",
|
||||
url: route('client.search.index'),
|
||||
params: {
|
||||
search: this.searchInput.toLowerCase(),
|
||||
page: page,
|
||||
category: this.selectedCategory
|
||||
}
|
||||
}).then((response) => {
|
||||
this.paginate = response.data.paginate
|
||||
this.result = response.data.searchRes;
|
||||
this.toggleLoadingState(false);
|
||||
});
|
||||
}, 500),
|
||||
|
||||
toggleLoadingState(state) {
|
||||
this.loading = state
|
||||
},
|
||||
|
||||
|
||||
textLimit(text, symbols) {
|
||||
if (text.length > symbols) {
|
||||
let LimitedText
|
||||
LimitedText = text.substring(0, symbols)
|
||||
return LimitedText + "..."
|
||||
}
|
||||
return text
|
||||
},
|
||||
},
|
||||
props: {
|
||||
open_id: {
|
||||
type: String,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hide-scrollbar::-webkit-scrollbar {
|
||||
display: none; /* Скрыть scrollbar для WebKit-браузеров */
|
||||
}
|
||||
.hide-scrollbar {
|
||||
-ms-overflow-style: none; /* Для Internet Explorer и Edge */
|
||||
scrollbar-width: none; /* Для Firefox */
|
||||
}
|
||||
|
||||
</style>
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<Link v-if="item.tag === 'AdditionalEducation'" data-hs-overlay="#hs-basic-modal" :href="route('client.additionalEducation.show', item.data.id)" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 16.875h3.375m0 0h3.375m-3.375 0V13.5m0 3.375v3.375M6 10.5h2.25a2.25 2.25 0 0 0 2.25-2.25V6a2.25 2.25 0 0 0-2.25-2.25H6A2.25 2.25 0 0 0 3.75 6v2.25A2.25 2.25 0 0 0 6 10.5Zm0 9.75h2.25A2.25 2.25 0 0 0 10.5 18v-2.25a2.25 2.25 0 0 0-2.25-2.25H6a2.25 2.25 0 0 0-2.25 2.25V18A2.25 2.25 0 0 0 6 20.25Zm9.75-9.75H18a2.25 2.25 0 0 0 2.25-2.25V6A2.25 2.25 0 0 0 18 3.75h-2.25A2.25 2.25 0 0 0 13.5 6v2.25a2.25 2.25 0 0 0 2.25 2.25Z" />
|
||||
</svg>
|
||||
|
||||
|
||||
<span class="text-sm">{{ item.data.title }}</span>
|
||||
</Link>
|
||||
<div v-if="item.matches.length !== 0" class="">
|
||||
<template v-for="match in item.matches.slice(0,3)">
|
||||
<div class="flex gap-3 px-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<div class="ml-[8px] flex h-12 w-full items-center gap-2 overflow-hidden border-l border-gray-200 px-4 pl-[22px] text-sm text-gray-900 md:h-10">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5" />
|
||||
</svg>
|
||||
<p class="truncate">{{ match }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
export default {
|
||||
name: "ResultAdditionalEducationItem",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
selectedCategory: 'All',
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div v-if="item.tag === 'EducationalGroup'" data-hs-overlay="#hs-basic-modal"
|
||||
class="my-1 flex gap-3 px-2 py-2 items-center rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||
class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5m-9-6h.008v.008H12v-.008ZM12 15h.008v.008H12V15Zm0 2.25h.008v.008H12v-.008ZM9.75 15h.008v.008H9.75V15Zm0 2.25h.008v.008H9.75v-.008ZM7.5 15h.008v.008H7.5V15Zm0 2.25h.008v.008H7.5v-.008Zm6.75-4.5h.008v.008h-.008v-.008Zm0 2.25h.008v.008h-.008V15Zm0 2.25h.008v.008h-.008v-.008Zm2.25-4.5h.008v.008H16.5v-.008Zm0 2.25h.008v.008H16.5V15Z"/>
|
||||
</svg>
|
||||
<span class="text-sm">{{ item.data.title }}</span>
|
||||
</div>
|
||||
<template v-for="schedule in item.data.schedules">
|
||||
<div class="mb-2">
|
||||
<div class="flex gap-3 px-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<Link href="/"
|
||||
class="ml-[8px] flex h-12 w-full items-center gap-2 overflow-hidden border-l border-gray-200 px-4 pl-[22px] text-sm text-gray-900 md:h-10">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor" class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5"/>
|
||||
</svg>
|
||||
<p class="truncate">{{ schedule.title }}</p>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
export default {
|
||||
name: "ResultEducationalGroupItem",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
selectedCategory: 'All',
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<Link v-if="item.tag === 'EducationalProgram'" data-hs-overlay="#hs-basic-modal" :href="route('client.program.show', item.data.slug)" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
|
||||
</svg>
|
||||
|
||||
<span class="text-sm">{{ item.data.name }}</span>
|
||||
</Link>
|
||||
<div v-if="item.matches.length !== 0" class="">
|
||||
<template v-for="match in item.matches.slice(0,3)">
|
||||
<div class="flex gap-3 px-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<div class="ml-[8px] flex h-12 w-full items-center gap-2 overflow-hidden border-l border-gray-200 px-4 pl-[22px] text-sm text-gray-900 md:h-10">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5" />
|
||||
</svg>
|
||||
<p class="truncate">{{ match }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
export default {
|
||||
name: "ResultEducationalProgramItem",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
selectedCategory: 'All',
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<Link v-if="item.tag === 'Event'" data-hs-overlay="#hs-basic-modal" :href="route('client.event.show', item.data.slug)" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 2.994v2.25m10.5-2.25v2.25m-14.252 13.5V7.491a2.25 2.25 0 0 1 2.25-2.25h13.5a2.25 2.25 0 0 1 2.25 2.25v11.251m-18 0a2.25 2.25 0 0 0 2.25 2.25h13.5a2.25 2.25 0 0 0 2.25-2.25m-18 0v-7.5a2.25 2.25 0 0 1 2.25-2.25h13.5a2.25 2.25 0 0 1 2.25 2.25v7.5m-6.75-6h2.25m-9 2.25h4.5m.002-2.25h.005v.006H12v-.006Zm-.001 4.5h.006v.006h-.006v-.005Zm-2.25.001h.005v.006H9.75v-.006Zm-2.25 0h.005v.005h-.006v-.005Zm6.75-2.247h.005v.005h-.005v-.005Zm0 2.247h.006v.006h-.006v-.006Zm2.25-2.248h.006V15H16.5v-.005Z" />
|
||||
</svg>
|
||||
|
||||
<span class="text-sm">{{ item.data.title }}</span>
|
||||
</Link>
|
||||
<div v-if="item.matches.length !== 0" class="">
|
||||
<template v-for="match in item.matches.slice(0,3)">
|
||||
<div class="flex gap-3 px-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<div class="ml-[8px] flex h-12 w-full items-center gap-2 overflow-hidden border-l border-gray-200 px-4 pl-[22px] text-sm text-gray-900 md:h-10">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5" />
|
||||
</svg>
|
||||
<p class="truncate">{{ match }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
export default {
|
||||
name: "ResultEventItem",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
selectedCategory: 'All',
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<a v-if="item.tag === 'Faculty'" data-hs-overlay="#hs-basic-modal" :href="route('client.faculty.show', item.data.slug)" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M18 18.72a9.094 9.094 0 0 0 3.741-.479 3 3 0 0 0-4.682-2.72m.94 3.198.001.031c0 .225-.012.447-.037.666A11.944 11.944 0 0 1 12 21c-2.17 0-4.207-.576-5.963-1.584A6.062 6.062 0 0 1 6 18.719m12 0a5.971 5.971 0 0 0-.941-3.197m0 0A5.995 5.995 0 0 0 12 12.75a5.995 5.995 0 0 0-5.058 2.772m0 0a3 3 0 0 0-4.681 2.72 8.986 8.986 0 0 0 3.74.477m.94-3.197a5.971 5.971 0 0 0-.94 3.197M15 6.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Zm6 3a2.25 2.25 0 1 1-4.5 0 2.25 2.25 0 0 1 4.5 0Zm-13.5 0a2.25 2.25 0 1 1-4.5 0 2.25 2.25 0 0 1 4.5 0Z" />
|
||||
</svg>
|
||||
<span class="text-sm">{{ item.data.title }}</span>
|
||||
</a>
|
||||
<!-- <div v-if="item.matches.length !== 0" class="">-->
|
||||
<!-- <template v-for="match in item.matches.slice(0,3)">-->
|
||||
<!-- <div class="flex gap-3 px-2 items-center hover:bg-[#F2F2F2] rounded-lg">-->
|
||||
<!-- <div class="ml-[8px] flex h-12 w-full items-center gap-2 overflow-hidden border-l border-gray-200 px-4 pl-[22px] text-sm text-gray-900 md:h-10">-->
|
||||
<!-- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">-->
|
||||
<!-- <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5" />-->
|
||||
<!-- </svg>-->
|
||||
<!-- <p class="truncate">{{ match }}</p>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<!-- </div>-->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
export default {
|
||||
name: "ResultFacultyItem",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
selectedCategory: 'All',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<Link v-if="item.tag === 'Page' && item.data.is_url == false" data-hs-overlay="#hs-basic-modal" :href="route('page.view', item.data.path) + '/'" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" />
|
||||
</svg>
|
||||
<span class="text-sm">{{ item.data.title }}</span>
|
||||
</Link>
|
||||
<a v-if="item.tag === 'Page' && item.data.is_url == true" data-hs-overlay="#hs-basic-modal" :href="item.data.path" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" />
|
||||
</svg>
|
||||
<span class="text-sm">{{ item.data.title }}</span>
|
||||
</a>
|
||||
<!-- <div v-if="item.matches.length !== 0" class="">-->
|
||||
<!-- <template v-for="match in item.matches.slice(0,3)">-->
|
||||
<!-- <div class="flex gap-3 px-2 items-center hover:bg-[#F2F2F2] rounded-lg">-->
|
||||
<!-- <div class="ml-[8px] flex h-12 w-full items-center gap-2 overflow-hidden border-l border-gray-200 px-4 pl-[22px] text-sm text-gray-900 md:h-10">-->
|
||||
<!-- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">-->
|
||||
<!-- <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5" />-->
|
||||
<!-- </svg>-->
|
||||
<!-- <p class="truncate">{{ match }}</p>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<!-- </div>-->
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
export default {
|
||||
name: "ResultPageItem",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
selectedCategory: 'All',
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<a v-if="item.tag === 'User'" data-hs-overlay="#hs-basic-modal" :href="route('client.person.show', item.data.slug)" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
|
||||
</svg>
|
||||
<span class="text-sm">{{ item.data.name }}</span>
|
||||
</a>
|
||||
<!-- <div v-if="item.matches.length !== 0" class="">-->
|
||||
<!-- <template v-for="match in item.matches.slice(0,3)">-->
|
||||
<!-- <div class="flex gap-3 px-2 items-center hover:bg-[#F2F2F2] rounded-lg">-->
|
||||
<!-- <div class="ml-[8px] flex h-12 w-full items-center gap-2 overflow-hidden border-l border-gray-200 px-4 pl-[22px] text-sm text-gray-900 md:h-10">-->
|
||||
<!-- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">-->
|
||||
<!-- <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5" />-->
|
||||
<!-- </svg>-->
|
||||
<!-- <p class="truncate">{{ match }}</p>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<!-- </div>-->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
export default {
|
||||
name: "ResultPersonItem",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
selectedCategory: 'All',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<a v-if="item.tag === 'Post'" data-hs-overlay="#hs-basic-modal" :href="route('client.post.show', item.data.slug)" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 7.5h1.5m-1.5 3h1.5m-7.5 3h7.5m-7.5 3h7.5m3-9h3.375c.621 0 1.125.504 1.125 1.125V18a2.25 2.25 0 0 1-2.25 2.25M16.5 7.5V18a2.25 2.25 0 0 0 2.25 2.25M16.5 7.5V4.875c0-.621-.504-1.125-1.125-1.125H4.125C3.504 3.75 3 4.254 3 4.875V18a2.25 2.25 0 0 0 2.25 2.25h13.5M6 7.5h3v3H6v-3Z" />
|
||||
</svg>
|
||||
<span class="text-sm">{{ item.data.title }}</span>
|
||||
</a>
|
||||
<!-- <div v-if="item.matches.length !== 0" class="">-->
|
||||
<!-- <template v-for="match in item.matches.slice(0,3)">-->
|
||||
<!-- <div class="flex gap-3 px-2 items-center hover:bg-[#F2F2F2] rounded-lg">-->
|
||||
<!-- <div class="ml-[8px] flex h-12 w-full items-center gap-2 overflow-hidden border-l border-gray-200 px-4 pl-[22px] text-sm text-gray-900 md:h-10">-->
|
||||
<!-- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">-->
|
||||
<!-- <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5" />-->
|
||||
<!-- </svg>-->
|
||||
<!-- <p class="truncate">{{ match }}</p>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<!-- </div>-->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
export default {
|
||||
name: "ResultPostItem",
|
||||
components: {Link},
|
||||
data() {
|
||||
return {
|
||||
selectedCategory: 'All',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<Link data-hs-overlay="#hs-basic-modal" :href="route('client.post.index')" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 7.5h1.5m-1.5 3h1.5m-7.5 3h7.5m-7.5 3h7.5m3-9h3.375c.621 0 1.125.504 1.125 1.125V18a2.25 2.25 0 0 1-2.25 2.25M16.5 7.5V18a2.25 2.25 0 0 0 2.25 2.25M16.5 7.5V4.875c0-.621-.504-1.125-1.125-1.125H4.125C3.504 3.75 3 4.254 3 4.875V18a2.25 2.25 0 0 0 2.25 2.25h13.5M6 7.5h3v3H6v-3Z" />
|
||||
</svg>
|
||||
<span class="text-sm">Новости</span>
|
||||
</Link>
|
||||
<Link data-hs-overlay="#hs-basic-modal" :href="route('client.event.index')" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M18 18.72a9.094 9.094 0 0 0 3.741-.479 3 3 0 0 0-4.682-2.72m.94 3.198.001.031c0 .225-.012.447-.037.666A11.944 11.944 0 0 1 12 21c-2.17 0-4.207-.576-5.963-1.584A6.062 6.062 0 0 1 6 18.719m12 0a5.971 5.971 0 0 0-.941-3.197m0 0A5.995 5.995 0 0 0 12 12.75a5.995 5.995 0 0 0-5.058 2.772m0 0a3 3 0 0 0-4.681 2.72 8.986 8.986 0 0 0 3.74.477m.94-3.197a5.971 5.971 0 0 0-.94 3.197M15 6.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Zm6 3a2.25 2.25 0 1 1-4.5 0 2.25 2.25 0 0 1 4.5 0Zm-13.5 0a2.25 2.25 0 1 1-4.5 0 2.25 2.25 0 0 1 4.5 0Z" />
|
||||
</svg>
|
||||
|
||||
<span class="text-sm">Мероприятия</span>
|
||||
</Link>
|
||||
<Link data-hs-overlay="#hs-basic-modal" :href="route('client.program.index')" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6.042A8.967 8.967 0 0 0 6 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 0 1 6 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 0 1 6-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0 0 18 18a8.967 8.967 0 0 0-6 2.292m0-14.25v14.25" />
|
||||
</svg>
|
||||
|
||||
<span class="text-sm">Приемная компания</span>
|
||||
</Link>
|
||||
<Link data-hs-overlay="#hs-basic-modal" :href="route('client.program.index')" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11.35 3.836c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75 2.25 2.25 0 0 0-.1-.664m-5.8 0A2.251 2.251 0 0 1 13.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m8.9-4.414c.376.023.75.05 1.124.08 1.131.094 1.976 1.057 1.976 2.192V16.5A2.25 2.25 0 0 1 18 18.75h-2.25m-7.5-10.5H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V18.75m-7.5-10.5h6.375c.621 0 1.125.504 1.125 1.125v9.375m-8.25-3 1.5 1.5 3-3.75" />
|
||||
</svg>
|
||||
|
||||
<span class="text-sm">Образовательные программы</span>
|
||||
</Link>
|
||||
<Link data-hs-overlay="#hs-basic-modal" :href="route('client.additionalEducation.index')" class="my-1 flex gap-3 px-2 py-2 items-center hover:bg-[#F2F2F2] rounded-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 7.125C2.25 6.504 2.754 6 3.375 6h6c.621 0 1.125.504 1.125 1.125v3.75c0 .621-.504 1.125-1.125 1.125h-6a1.125 1.125 0 0 1-1.125-1.125v-3.75ZM14.25 8.625c0-.621.504-1.125 1.125-1.125h5.25c.621 0 1.125.504 1.125 1.125v8.25c0 .621-.504 1.125-1.125 1.125h-5.25a1.125 1.125 0 0 1-1.125-1.125v-8.25ZM3.75 16.125c0-.621.504-1.125 1.125-1.125h5.25c.621 0 1.125.504 1.125 1.125v2.25c0 .621-.504 1.125-1.125 1.125h-5.25a1.125 1.125 0 0 1-1.125-1.125v-2.25Z" />
|
||||
</svg>
|
||||
|
||||
<span class="text-sm">Курсы дополнительного образования</span>
|
||||
</Link>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
|
||||
export default {
|
||||
name: "PreSearchLinkList",
|
||||
components: {Link},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<PreSearchLinkList v-if="result === null" class="px-2 font-light" />
|
||||
<div v-else-if="result.length !== 0"
|
||||
:class="{'filter': loading === true}"
|
||||
class="px-2 font-light duration-300">
|
||||
<template v-for="(elements, tag) in result">
|
||||
<component
|
||||
v-for="(item, index) in elements"
|
||||
:key="index"
|
||||
:is="getComponent(tag)"
|
||||
:item="item"
|
||||
v-if="selectedCategory === null || selectedCategory === tag"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import PreSearchLinkList from "@/componentss/features/search/components/PreSearchLinkList.vue";
|
||||
import ResultPostItem from "@/componentss/features/search/components/Items/ResultPostItem.vue";
|
||||
import ResultPageItem from "@/componentss/features/search/components/Items/ResultPagetItem.vue";
|
||||
import ResultEducationalProgramItem
|
||||
from "@/componentss/features/search/components/Items/ResultEducationalProgramItem.vue";
|
||||
import ResultEventItem from "@/componentss/features/search/components/Items/ResultEventItem.vue";
|
||||
import ResultPersonItem from "@/componentss/features/search/components/Items/ResultPersonItem.vue";
|
||||
import ResultFacultyItem from "@/componentss/features/search/components/Items/ResultFacultyItem.vue";
|
||||
import ResultEducationalGroupItem from "@/componentss/features/search/components/Items/ResultEducationalGroupItem.vue";
|
||||
import ResultAdditionalEducationItem
|
||||
from "@/componentss/features/search/components/Items/ResultAdditionalEducationItem.vue";
|
||||
|
||||
|
||||
export default {
|
||||
name: "ResultList",
|
||||
components: {
|
||||
ResultEducationalGroupItem,
|
||||
ResultAdditionalEducationItem,
|
||||
ResultEventItem,
|
||||
ResultEducationalProgramItem,
|
||||
ResultPageItem,
|
||||
ResultPostItem,
|
||||
PreSearchLinkList,
|
||||
ResultPersonItem,
|
||||
ResultFacultyItem,
|
||||
Link},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getComponent(type) {
|
||||
const componentMap = {
|
||||
Post: 'ResultPostItem',
|
||||
Page: 'ResultPageItem',
|
||||
Event: 'ResultEventItem',
|
||||
EducationalProgram: 'ResultEducationalProgramItem',
|
||||
AdditionalEducational: 'ResultAdditionalEducationItem',
|
||||
EducationalGroup: 'ResultEducationalGroupItem',
|
||||
User: 'ResultPersonItem',
|
||||
Faculty: 'ResultFacultyItem'
|
||||
};
|
||||
return componentMap[type] || null;
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
props: {
|
||||
result: {
|
||||
type: Object,
|
||||
},
|
||||
selectedCategory: {
|
||||
type: String,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.filter {
|
||||
filter: saturate(100%) blur(3px);
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "PostSearchCategory"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div v-if="loading" class="relative z-0 min-h-[calc(100vh)] items-center">
|
||||
<div class="group block rounded-xl overflow-hidden animate-pulse min-h-[calc(100vh)] bg-gray-200"></div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<SliderBody :slides="slider.slides" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import SliderBody from "@/componentss/features/sliders/components/SliderBody.vue";
|
||||
|
||||
export default {
|
||||
name: 'Slider',
|
||||
components: {SliderBody},
|
||||
props: {
|
||||
sliderId: {
|
||||
type: String,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
slider: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getSlider(id) {
|
||||
axios.get(route('client.widget.slider.show', id))
|
||||
.then(response => {
|
||||
this.slider = response.data;
|
||||
this.loading = false; // Установить состояние загрузки в false
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Ошибка:', error);
|
||||
});
|
||||
},
|
||||
|
||||
},
|
||||
mounted() {
|
||||
const id = this.sliderId
|
||||
this.getSlider(id)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<div ref="sliderRef" class="relative z-0 min-h-[calc(70vh)] items-center">
|
||||
<!-- Слайды с изображениями -->
|
||||
<a
|
||||
:href="(!slide.settings.link_text) ? slide.link : '#'"
|
||||
v-for="(slide, index) in slides"
|
||||
:key="index"
|
||||
:style="{ filter: `brightness(${slide.image.shading})` }"
|
||||
class="absolute -z-10 h-full w-full before:absolute before:z-10 before:h-full before:w-full"
|
||||
>
|
||||
<img
|
||||
alt="Thumbnail"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
data-nimg="fill"
|
||||
class="object-cover rounded-md transition-opacity duration-1000 absolute inset-0 h-full w-full"
|
||||
sizes="100vw"
|
||||
:src="'/storage/' + slide.image.url"
|
||||
:class="{ 'opacity-1': currentIndex === index, 'opacity-0': currentIndex !== index }"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<!-- Текст слайдов с анимацией -->
|
||||
<transition name="fade" mode="out-in">
|
||||
<div :key="currentIndex">
|
||||
<div
|
||||
v-show="currentIndex === index"
|
||||
v-for="(item, index) in slides"
|
||||
:key="index"
|
||||
class="mx-auto max-w-screen-md px-5 pt-[150px] pb-0 bvi-no-styles"
|
||||
>
|
||||
<h1
|
||||
v-if="item.title"
|
||||
:class="`text-${item.settings.text_position}`"
|
||||
class="text-brand-primary mb-3 mt-2 text-3xl font-semibold tracking-tight text-white lg:text-5xl lg:leading-tight"
|
||||
>
|
||||
{{ item.title }}
|
||||
</h1>
|
||||
<div v-if="item.content" class="mt-8 space-x-3 text-gray-500 mb-8">
|
||||
<div class="gap-3 md:flex-row md:items-center">
|
||||
<div class="gap-3">
|
||||
<p :class="`text-${item.settings.text_position}`" class="text-gray-100 line-clamp-3">
|
||||
{{ item.content }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`text-${item.settings.text_position}`">
|
||||
<a
|
||||
v-if="item.settings.link_text"
|
||||
:href="item.link"
|
||||
class="py-3 px-4 inline-flex items-center duration-300 gap-x-2 text-sm font-semibold rounded-lg border border-white text-white bg-transparent hover:bg-white hover:text-black hover:mix-blend-screen disabled:opacity-50 disabled:pointer-events-none"
|
||||
>
|
||||
{{ item.settings.link_text }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<!-- Кнопки управления и прогресс-бар -->
|
||||
<div v-if="slides.length >= 2" class="mx-auto max-w-screen-md px-5">
|
||||
<div class="mt-8 text-gray-500 absolute bottom-[50px] left-1/2 transform -translate-x-1/2 lg:bottom-[100px]">
|
||||
<div class="">
|
||||
<div class="flex space-x-3 items-center justify-between">
|
||||
<button @click="prev" class="bg-gray-200 w-8 h-8 hover:bg-gray-300 text-gray-800 font-bold rounded-full">
|
||||
<svg class="w-4 h-4 mx-auto my-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div class="flex space-x-3 w-[200px] items-center font-semibold text-xl text-white">
|
||||
<span>{{ currentIndex + 1 }}</span>
|
||||
<div class="flex w-full h-1 bg-gray-200 rounded-full overflow-hidden" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">
|
||||
<div class="flex flex-col justify-center rounded-full overflow-hidden bg-blue-600 text-xs text-white text-center whitespace-nowrap transition-all duration-500 ease-in-out" :style="{ 'width': `${progressBarStep}%` }"></div>
|
||||
</div>
|
||||
<span>{{ slides.length }}</span>
|
||||
</div>
|
||||
|
||||
<button @click="next" class="bg-gray-200 w-8 h-8 hover:bg-gray-300 text-gray-800 font-bold rounded-full">
|
||||
<svg class="w-4 h-4 mx-auto my-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19l7-7-7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from "vuex";
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
name: 'SliderBlockBody',
|
||||
props: {
|
||||
slides: {
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentIndex: 0,
|
||||
intervalId: null,
|
||||
slideDuration: 5000,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
totalSlides() {
|
||||
return this.slides && this.slides ? this.slides.length : 0;
|
||||
},
|
||||
progressBarStep() {
|
||||
const slides = this.totalSlides;
|
||||
const step = 100 / slides;
|
||||
return (this.currentIndex + 1) * step;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['updateLastSlider']),
|
||||
next() {
|
||||
if (this.totalSlides > 0) {
|
||||
this.currentIndex = (this.currentIndex + 1) % this.totalSlides;
|
||||
this.resetTimer();
|
||||
}
|
||||
},
|
||||
prev() {
|
||||
if (this.totalSlides > 0) {
|
||||
this.currentIndex = (this.currentIndex - 1 + this.totalSlides) % this.totalSlides;
|
||||
this.resetTimer();
|
||||
}
|
||||
},
|
||||
startTimer() {
|
||||
this.stopTimer();
|
||||
this.intervalId = setInterval(this.next, this.slideDuration);
|
||||
},
|
||||
stopTimer() {
|
||||
clearInterval(this.intervalId);
|
||||
},
|
||||
resetTimer() {
|
||||
this.stopTimer();
|
||||
this.startTimer();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// Передаем данные в Vuex после монтирования компонента
|
||||
this.updateLastSlider({
|
||||
url: this.$page.props.ziggy.location,
|
||||
top: this.$refs.sliderRef.getBoundingClientRect().top,
|
||||
bottom: this.$refs.sliderRef.getBoundingClientRect().bottom, // Получаем актуальное значение bottom
|
||||
});
|
||||
this.startTimer();
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.stopTimer();
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
/* Стили для изображений слайдов */
|
||||
.opacity-1 {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.opacity-0 {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<div ref="sliderRef" class="relative z-0 min-h-[calc(100vh)] items-center">
|
||||
<!-- Слайды с изображениями -->
|
||||
<a
|
||||
:href="(!slide.settings.link_text) ? slide.link : '#'"
|
||||
v-for="(slide, index) in slides"
|
||||
:key="index"
|
||||
:style="{ filter: `brightness(${slide.image.shading})` }"
|
||||
class="absolute -z-10 h-full w-full before:absolute before:z-10 before:h-full before:w-full"
|
||||
>
|
||||
<img
|
||||
alt="Thumbnail"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
data-nimg="fill"
|
||||
class="object-cover transition-opacity duration-1000 absolute inset-0 h-full w-full"
|
||||
sizes="100vw"
|
||||
:src="'/storage/' + slide.image.url"
|
||||
:class="{ 'opacity-1': currentIndex === index, 'opacity-0': currentIndex !== index }"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<!-- Текст слайдов с анимацией -->
|
||||
<transition name="fade" mode="out-in">
|
||||
<div :key="currentIndex">
|
||||
<div
|
||||
v-show="currentIndex === index"
|
||||
v-for="(item, index) in slides"
|
||||
:key="index"
|
||||
class="mx-auto max-w-screen-md px-5 pt-[150px] pb-0 bvi-no-styles"
|
||||
>
|
||||
<h1
|
||||
v-if="item.title"
|
||||
:class="`text-${item.settings.text_position}`"
|
||||
class="text-brand-primary mb-3 mt-2 text-3xl font-semibold tracking-tight text-white lg:text-5xl lg:leading-tight"
|
||||
>
|
||||
{{ item.title }}
|
||||
</h1>
|
||||
<div v-if="item.content" class="mt-8 space-x-3 text-gray-500 mb-8">
|
||||
<div class="gap-3 md:flex-row md:items-center">
|
||||
<div class="gap-3">
|
||||
<p :class="`text-${item.settings.text_position}`" class="text-gray-100 line-clamp-3">
|
||||
{{ item.content }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`text-${item.settings.text_position}`">
|
||||
<a
|
||||
v-if="item.settings.link_text"
|
||||
:href="item.link"
|
||||
class="py-3 px-4 inline-flex items-center duration-300 gap-x-2 text-sm font-semibold rounded-lg border border-white text-white bg-transparent hover:bg-white hover:text-black hover:mix-blend-screen disabled:opacity-50 disabled:pointer-events-none"
|
||||
>
|
||||
{{ item.settings.link_text }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<!-- Кнопки управления и прогресс-бар -->
|
||||
<div v-if="slides.length >= 2" class="mx-auto max-w-screen-md px-5">
|
||||
<div class="mt-8 text-gray-500 absolute bottom-[50px] left-1/2 transform -translate-x-1/2 lg:bottom-[100px]">
|
||||
<div class="">
|
||||
<div class="flex space-x-3 items-center justify-between">
|
||||
<button @click="prev" class="bg-gray-200 w-8 h-8 hover:bg-gray-300 text-gray-800 font-bold rounded-full">
|
||||
<svg class="w-4 h-4 mx-auto my-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div class="flex space-x-3 w-[200px] items-center font-semibold text-xl text-white">
|
||||
<span>{{ currentIndex + 1 }}</span>
|
||||
<div class="flex w-full h-1 bg-gray-200 rounded-full overflow-hidden" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">
|
||||
<div class="flex flex-col justify-center rounded-full overflow-hidden bg-blue-600 text-xs text-white text-center whitespace-nowrap transition-all duration-500 ease-in-out" :style="{ 'width': `${progressBarStep}%` }"></div>
|
||||
</div>
|
||||
<span>{{ slides.length }}</span>
|
||||
</div>
|
||||
|
||||
<button @click="next" class="bg-gray-200 w-8 h-8 hover:bg-gray-300 text-gray-800 font-bold rounded-full">
|
||||
<svg class="w-4 h-4 mx-auto my-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19l7-7-7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from "vuex";
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
name: 'SliderBody',
|
||||
props: {
|
||||
slides: {
|
||||
type: Object,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentIndex: 0,
|
||||
intervalId: null,
|
||||
slideDuration: 5000,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
totalSlides() {
|
||||
return this.slides && this.slides ? this.slides.length : 0;
|
||||
},
|
||||
progressBarStep() {
|
||||
const slides = this.totalSlides;
|
||||
const step = 100 / slides;
|
||||
return (this.currentIndex + 1) * step;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['updateLastSlider']),
|
||||
next() {
|
||||
if (this.totalSlides > 0) {
|
||||
this.currentIndex = (this.currentIndex + 1) % this.totalSlides;
|
||||
this.resetTimer();
|
||||
}
|
||||
},
|
||||
prev() {
|
||||
if (this.totalSlides > 0) {
|
||||
this.currentIndex = (this.currentIndex - 1 + this.totalSlides) % this.totalSlides;
|
||||
this.resetTimer();
|
||||
}
|
||||
},
|
||||
startTimer() {
|
||||
this.stopTimer();
|
||||
this.intervalId = setInterval(this.next, this.slideDuration);
|
||||
},
|
||||
stopTimer() {
|
||||
clearInterval(this.intervalId);
|
||||
},
|
||||
resetTimer() {
|
||||
this.stopTimer();
|
||||
this.startTimer();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// Передаем данные в Vuex после монтирования компонента
|
||||
this.updateLastSlider({
|
||||
url: this.$page.props.ziggy.location,
|
||||
top: this.$refs.sliderRef.getBoundingClientRect().top,
|
||||
bottom: this.$refs.sliderRef.getBoundingClientRect().bottom, // Получаем актуальное значение bottom
|
||||
});
|
||||
this.startTimer();
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.stopTimer();
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
/* Стили для изображений слайдов */
|
||||
.opacity-1 {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.opacity-0 {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div v-if="loading" class="relative z-0 min-h-[calc(100vh)] items-center">
|
||||
<div class="group block rounded-xl overflow-hidden animate-pulse min-h-[calc(100vh)] bg-gray-200"></div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<SliderBlockBody :slides="slider.slides" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import SliderBlockBody from "@/componentss/features/sliders/components/SliderBlockBody.vue";
|
||||
|
||||
export default {
|
||||
name: 'SliderBlock',
|
||||
components: {SliderBlockBody},
|
||||
props: {
|
||||
block: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
slider: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
totalSlides() {
|
||||
return this.slidersCarousel && this.slidersCarousel.data ? this.slidersCarousel.data.length : 0;
|
||||
},
|
||||
progressBarStep() {
|
||||
const slides = this.totalSlides;
|
||||
const step = 100 / slides;
|
||||
return (this.currentIndex + 1) * step;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getSlider(id) {
|
||||
axios.get(route('client.widget.slider.show', id))
|
||||
.then(response => {
|
||||
this.slider = response.data;
|
||||
this.loading = false; // Установить состояние загрузки в false
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Ошибка:', error);
|
||||
});
|
||||
},
|
||||
|
||||
},
|
||||
mounted() {
|
||||
const id = this.block?.data.slider
|
||||
this.getSlider(id)
|
||||
},
|
||||
beforeUnmount() {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user