This commit is contained in:
f4ilji
2025-01-10 15:45:31 +05:00
parent 1cc64c390d
commit 8106493216
4 changed files with 203 additions and 53 deletions
@@ -23,6 +23,7 @@ class ClientScheduleController extends Controller
$query->whereRaw('LOWER(title) like ?', ["%".strtolower($search)."%"]); $query->whereRaw('LOWER(title) like ?', ["%".strtolower($search)."%"]);
}) })
->with('schedules') ->with('schedules')
->with('faculty')
->orderBy('title') ->orderBy('title')
->get()); ->get());
} }
@@ -18,6 +18,7 @@ class ClientEducationalGroupResource extends JsonResource
'id' => $this->id, 'id' => $this->id,
'title' => $this->title, 'title' => $this->title,
'schedules' => ClientScheduleSearchResource::collection($this->schedules), 'schedules' => ClientScheduleSearchResource::collection($this->schedules),
'faculty' => $this->faculty->title,
]; ];
} }
} }
+11 -1
View File
@@ -62,7 +62,17 @@ export default {
stroke_width: 1.5, stroke_width: 1.5,
stroke: 'currentColor', stroke: 'currentColor',
}, },
home: { heart_filled: {
path: '<path d="m11.645 20.91-.007-.003-.022-.012a15.247 15.247 0 0 1-.383-.218 25.18 25.18 0 0 1-4.244-3.17C4.688 15.36 2.25 12.174 2.25 8.25 2.25 5.322 4.714 3 7.688 3A5.5 5.5 0 0 1 12 5.052 5.5 5.5 0 0 1 16.313 3c2.973 0 5.437 2.322 5.437 5.25 0 3.925-2.438 7.111-4.739 9.256a25.175 25.175 0 0 1-4.244 3.17 15.247 15.247 0 0 1-.383.219l-.022.012-.007.004-.003.001a.752.752 0 0 1-.704 0l-.003-.001Z"/>',
viewBox: '0 0 24 24',
fill: 'red', // Заливка красным цветом
// stroke_width: 1.5,
// stroke: 'currentColor',
},
home: {
path: '<path stroke-linecap="round" stroke-linejoin="round" d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25"/>', path: '<path stroke-linecap="round" stroke-linejoin="round" d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25"/>',
viewBox: '0 0 24 24', viewBox: '0 0 24 24',
fill: 'none', fill: 'none',
+161 -23
View File
@@ -1,18 +1,19 @@
<script> <script>
import MainNavbar from "@/Navbars/MainNavbar.vue"; import MainNavbar from "@/Navbars/MainNavbar.vue";
import ClientFooterDown from "@/Components/ClientFooterDown.vue"; import ClientFooterDown from "@/Components/ClientFooterDown.vue";
import {debounce} from "lodash"; import { debounce } from "lodash";
import {Link} from "@inertiajs/vue3"; import { Link } from "@inertiajs/vue3";
import MainPageNavBar from "@/Navbars/MainPageNavbar.vue"; import MainPageNavBar from "@/Navbars/MainPageNavbar.vue";
import BaseIcon from "@/Components/BaseComponents/BaseIcon.vue"; import BaseIcon from "@/Components/BaseComponents/BaseIcon.vue";
export default { export default {
name: "Index", name: "Index",
data() { data() {
return { return {
searchInput: this.searchRequest, searchInput: this.searchRequest,
} favoriteGroups: JSON.parse(localStorage.getItem('favoriteGroups')) || [],
showFavorites: false,
};
}, },
components: {BaseIcon, MainPageNavBar, ClientFooterDown, MainNavbar, Link}, components: {BaseIcon, MainPageNavBar, ClientFooterDown, MainNavbar, Link},
props: [ props: [
@@ -32,9 +33,31 @@ export default {
replace: true, replace: true,
}); });
}, 300), }, 300),
toggleFavorite(group) {
const index = this.favoriteGroups.findIndex(g => g.id === group.id);
if (index === -1) {
this.favoriteGroups.push(group);
} else {
this.favoriteGroups.splice(index, 1);
}
localStorage.setItem('favoriteGroups', JSON.stringify(this.favoriteGroups));
}, },
isFavorite(group) {
} return this.favoriteGroups.some(g => g.id === group.id);
},
toggleShowFavorites() {
this.showFavorites = !this.showFavorites;
},
},
computed: {
filteredGroups() {
if (this.showFavorites) {
return this.educationalGroups.data.filter(group => this.favoriteGroups.some(g => g.id === group.id));
}
return this.educationalGroups.data;
},
},
};
</script> </script>
<template> <template>
@@ -51,13 +74,13 @@ export default {
Расписание занятий Расписание занятий
</h1> </h1>
<div class="text-center"> <div class="text-center">
<p class="mt-3 text-gray-600 dark:text-gray-400"> <p class="mt-3 text-gray-600 dark:text-gray-400">
Просто введите название группы Просто введите название группы
</p> </p>
</div> </div>
<div class="mt-7 sm:mt-12 mx-auto max-w-xl relative space-y-4"> <div class="mt-7 sm:mt-12 mx-auto max-w-xl relative space-y-4">
<!-- Form --> <!-- Form -->
<form> <form>
@@ -68,40 +91,80 @@ export default {
class="block text-sm text-gray-700 font-medium dark:text-white"> class="block text-sm text-gray-700 font-medium dark:text-white">
<span class="sr-only">Поиск</span> <span class="sr-only">Поиск</span>
</label> </label>
<input @keydown.enter.prevent autocomplete="off" v-model="searchInput" @input="search" type="search" <input
@keydown.enter.prevent
autocomplete="off"
v-model="searchInput"
@input="search"
type="search"
id="hs-search-article-1" id="hs-search-article-1"
class="py-2.5 px-4 block w-full border-transparent rounded-lg" class="py-2.5 px-4 block w-full border-transparent rounded-lg disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-gray-100"
placeholder="Поиск"> placeholder="Поиск"
:disabled="showFavorites"
>
</div> </div>
</div> </div>
</div> </div>
</form> </form>
<div class=""> <div class="">
<div class="grid grid-cols-2 gap-3"> <div class="grid grid-cols-2 gap-3">
<button type="button" 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-blue-700 disabled:opacity-50 disabled:pointer-events-none"> <button @click="toggleShowFavorites" type="button"
<BaseIcon name="heart" class="shrink-0 size-4" /> :class="showFavorites ? 'bg-primaryBlue text-white hover:bg-secondDarkBlue' : 'text-gray-700 hover:bg-gray-100'"
class="flex w-full py-2 px-4 items-center gap-x-2 text-xs font-medium rounded-lg border border-gray-200 focus:outline-none disabled:opacity-50 disabled:pointer-events-none">
<BaseIcon name="heart" class="shrink-0 size-4"/>
<span>Избранные расписания</span> <span>Избранные расписания</span>
</button> </button>
<button type="button" 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-blue-700 disabled:opacity-50 disabled:pointer-events-none"> <button type="button"
<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="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" x2="19" y1="8" y2="14"/><line x1="22" x2="16" y1="11" y2="11"/></svg> 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">
<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="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<line x1="19" x2="19" y1="8" y2="14"/>
<line x1="22" x2="16" y1="11" y2="11"/>
</svg>
<span>Follow</span> <span>Follow</span>
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="mx-auto max-w-2xl hs-accordion-group grid grid-cols-1 lg:grid-cols-2 gap-3"> <div class="mx-auto max-w-2xl hs-accordion-group grid grid-cols-1 lg:grid-cols-2 gap-3">
<div v-if="!showFavorites">
<transition-group name="fade"> <transition-group name="fade">
<template v-for="educationalGroup in educationalGroups.data" :key="educationalGroup.id"> <template v-for="educationalGroup in filteredGroups" :key="educationalGroup.id">
<div class="hs-accordion hs-accordion-active:border-gray-200 bg-white border-b dark:hs-accordion-active:border-gray-700 dark:bg-gray-800 dark:border-transparent" <div
class="hs-accordion hs-accordion-active:border-gray-200 bg-white border-b dark:hs-accordion-active:border-gray-700 dark:bg-gray-800 dark:border-transparent"
id="hs-active-bordered-heading-one"> id="hs-active-bordered-heading-one">
<button class="hs-accordion-toggle hs-accordion-active:text-blue-600 inline-flex justify-between items-center gap-x-3 w-full font-semibold text-start text-gray-800 py-4 px-5 hover:text-gray-500 disabled:opacity-50 disabled:pointer-events-none dark:hs-accordion-active:text-blue-500 dark:text-gray-200 dark:hover:text-gray-400 dark:focus:outline-none dark:focus:text-gray-400" <div class="flex">
<button @click="toggleFavorite(educationalGroup)">
<transition name="heart" mode="out-in">
<BaseIcon
v-if="isFavorite(educationalGroup)"
name="heart_filled"
class="shrink-0 size-4 text-red-500"
key="filled"
/>
<BaseIcon
v-else
name="heart"
class="shrink-0 size-4"
key="outline"
/>
</transition>
</button>
<button
class="hs-accordion-toggle hs-accordion-active:text-blue-600 inline-flex justify-between items-center gap-x-3 w-full font-semibold text-start text-gray-800 py-4 px-5 hover:text-gray-500 disabled:opacity-50 disabled:pointer-events-none dark:hs-accordion-active:text-blue-500 dark:text-gray-200 dark:hover:text-gray-400 dark:focus:outline-none dark:focus:text-gray-400"
aria-controls="hs-basic-active-bordered-collapse-one"> aria-controls="hs-basic-active-bordered-collapse-one">
{{ educationalGroup.title }}
<div class="flex items-center gap-x-2"><span>{{ educationalGroup.title }}</span> <span
class="font-light text-sm uppercase text-gray-500">{{ educationalGroup.faculty }}</span></div>
<svg class="hs-accordion-active:hidden block w-3.5 h-3.5" <svg class="hs-accordion-active:hidden block w-3.5 h-3.5"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
@@ -116,34 +179,109 @@ export default {
<path d="M5 12h14"/> <path d="M5 12h14"/>
</svg> </svg>
</button> </button>
</div>
<div id="hs-basic-active-bordered-collapse-one" <div id="hs-basic-active-bordered-collapse-one"
class="hs-accordion-content hidden w-full overflow-hidden transition-[height] duration-300" class="hs-accordion-content hidden w-full overflow-hidden transition-[height] duration-300"
aria-labelledby="hs-active-bordered-heading-one"> aria-labelledby="hs-active-bordered-heading-one">
<div class="pb-4 px-5 grid gap-3 grid-cols-1"> <div class="pb-4 px-5 grid gap-3 grid-cols-1">
<template v-for="schedule in educationalGroup.schedules" :key="schedule.id"> <template v-for="schedule in educationalGroup.schedules" :key="schedule.id">
<template v-for="file in schedule.file"> <template v-for="file in schedule.file">
<a :href="'storage/' + file.path" target="_blank" class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-500 shadow-sm hover:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-800 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600"> <a :href="'storage/' + file.path" target="_blank"
class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-500 shadow-sm hover:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-800 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600">
{{ file.title }} {{ file.title }}
</a> </a>
</template> </template>
</template> </template>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
</transition-group> </transition-group>
</div> </div>
<div v-else>
<transition-group name="fade">
<template v-for="educationalGroup in favoriteGroups" :key="educationalGroup.id">
<div
class="hs-accordion hs-accordion-active:border-gray-200 bg-white border-b dark:hs-accordion-active:border-gray-700 dark:bg-gray-800 dark:border-transparent"
id="hs-active-bordered-heading-one">
<div class="flex">
<button @click="toggleFavorite(educationalGroup)">
<transition name="heart" mode="out-in">
<BaseIcon
v-if="isFavorite(educationalGroup)"
name="heart_filled"
class="shrink-0 size-4 text-red-500"
key="filled"
/>
<BaseIcon
v-else
name="heart"
class="shrink-0 size-4"
key="outline"
/>
</transition>
</button>
<button
class="hs-accordion-toggle hs-accordion-active:text-blue-600 inline-flex justify-between items-center gap-x-3 w-full font-semibold text-start text-gray-800 py-4 px-5 hover:text-gray-500 disabled:opacity-50 disabled:pointer-events-none dark:hs-accordion-active:text-blue-500 dark:text-gray-200 dark:hover:text-gray-400 dark:focus:outline-none dark:focus:text-gray-400"
aria-controls="hs-basic-active-bordered-collapse-one">
<div class="flex items-center gap-x-2"><span>{{ educationalGroup.title }}</span> <span
class="font-light text-sm uppercase text-gray-500">{{ educationalGroup.faculty }}</span></div>
<svg class="hs-accordion-active:hidden block w-3.5 h-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="M5 12h14"/>
<path d="M12 5v14"/>
</svg>
<svg class="hs-accordion-active:block hidden w-3.5 h-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="M5 12h14"/>
</svg>
</button>
</div>
<div id="hs-basic-active-bordered-collapse-one"
class="hs-accordion-content hidden w-full overflow-hidden transition-[height] duration-300"
aria-labelledby="hs-active-bordered-heading-one">
<div class="pb-4 px-5 grid gap-3 grid-cols-1">
<template v-for="schedule in educationalGroup.schedules" :key="schedule.id">
<template v-for="file in schedule.file">
<a :href="'storage/' + file.path" target="_blank"
class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-500 shadow-sm hover:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-800 dark:focus:outline-none dark:focus:ring-1 dark:focus:ring-gray-600">
{{ file.title }}
</a>
</template>
</template>
</div>
</div>
</div>
</template>
</transition-group>
</div>
</div>
</article> </article>
</div> </div>
</main> </main>
<ClientFooterDown/> <ClientFooterDown/>
</div> </div>
</template> </template>
<style scoped> <style scoped>
.heart-enter-active,
.heart-leave-active {
transition: opacity 0.1s ease;
}
.heart-enter-from,
.heart-leave-to {
opacity: 0;
}
.fade-enter-active, .fade-enter-active,
.fade-leave-active { .fade-leave-active {
transition: all 0.5s ease; transition: all 0.5s ease;