Initial commit

This commit is contained in:
Developer
2025-04-21 16:03:20 +02:00
commit 2832896157
22874 changed files with 3092801 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
<template>
<meta-head title="Авторизация">
<meta name="description" content="Авторизация">
</meta-head>
<div class="header-simple flex items-center justify-center p-2 bg-orange">
<img class="block h-12" src="/image/logotype.svg" alt="">
</div>
<div class="min-h-[calc(100vh-64px)] place-items-center grid md:pt-3"
style="background-image: url('/image/auth-bg.jpg');">
<div class="w-full md:w-auto max-w-7xl mx-auto ">
<div class="md:grid grid-cols-12 ">
<div class="col-span-7 bg-indigo-200">
<div class="p-4 lg:p-28">
<h1 class="font-medium text-xl md:text-2xl lg:text-4xl text-white text-center">Войти</h1>
<div class="auth-form mt-7">
<form @submit.prevent="submit" class="space-y-6">
<div>
<div class="relative">
<div class="absolute inset-y-0 left-5 text-gray flex items-center">
<svg 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" class="flex-shrink-0">
<path
d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z">
</path>
<polyline points="22,6 12,13 2,6"></polyline>
</svg>
</div>
<input
v-model="form.email"
autocapitalize="off"
class="w-full pl-14 h-12 md:h-16 focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border-transparent bg-indigo-100 rounded-md placeholder-gray"
type="email" placeholder="E-mail">
</div>
<div v-if="form.errors.email" class="form-error text-sm text-red">{{ form.errors.email }}</div>
</div>
<div>
<div class="relative">
<div class="absolute inset-y-0 left-5 text-gray flex items-center">
<svg 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" class="flex-shrink-0">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
</div>
<input
v-model="form.password"
class="w-full pl-14 h-12 md:h-16 focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border-transparent bg-indigo-100 rounded-md placeholder-gray"
type="password" placeholder="Пароль">
</div>
<div v-if="form.errors.password" class="form-error text-sm text-red">{{ form.errors.password }}</div>
</div>
<div class="flex items-center">
<input id="remember" v-model="form.remember" type="checkbox" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="remember" class="select-none ml-3 text-gray">Запомни меня</label>
</div>
<div class="text-center">
<loading-button :loading="form.processing" class="mx-3 my-1 px-12 py-3 transition shadow-none hover:shadow-classic2 inline-flex items-center justify-center text-base rounded-full text-white bg-orange focus:outline-none" type="submit">Войти</loading-button>
</div>
</form>
</div>
</div>
</div>
<div class="col-span-5 bg-center bg-cover" style="background-image: url('image/orange-auth.jpg');">
<div class="py-4 lg:py-28 px-4">
<div class="font-medium text-xl md:text-2xl lg:text-4xl !leading-relaxed text-white text-center">Заработай на своем
творчестве первый миллион </div>
<div class="font-medium text-xl md:text-2xl lg:text-4xl !leading-relaxed text-white text-center">Присоединяйся к 4Teaser
прямо сейчас!</div>
<div class="text-center mt-4 md:mt-10">
<inertia-link
:href="route('register')"
class="mx-3 my-1 px-12 py-3 transition shadow-none hover:shadow-classic2 inline-flex items-center justify-center text-base rounded-full text-white border border-white bg-transparent focus:outline-none">
Зарегистрироваться
</inertia-link>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { Inertia } from "@inertiajs/inertia";
import LoadingButton from "@/Shared/Form/LoadingButton";
import MetaHead from '@/Shared/MetaHead'
export default {
components: {
MetaHead,
LoadingButton,
},
setup() {
const form = Inertia.form({
email: null,
password: null,
remember: false,
});
const submit = () => {
form.post(route("login.store"));
};
return {
form,
submit,
};
},
}
</script>

View File

@@ -0,0 +1,135 @@
<template>
<meta-head title="Авторизация">
<meta name="description" content="Авторизация">
</meta-head>
<div class="header-simple flex items-center justify-center p-2 bg-orange">
<img class="block h-12" src="/image/logotype.svg" alt="">
</div>
<div class="min-h-[calc(100vh-64px)] place-items-center grid md:pt-3"
style="background-image: url('/image/auth-bg.jpg');">
<div class="w-full md:w-auto max-w-7xl mx-auto ">
<div class="md:grid grid-cols-12 ">
<div class="col-span-7 bg-indigo-200">
<div class="p-4 lg:p-28">
<h1 class="font-medium text-xl md:text-2xl lg:text-4xl text-white text-center">Регистрация</h1>
<div class="auth-form mt-7">
<form @submit.prevent="submit" class="space-y-6">
<div>
<div class="relative">
<div class="absolute inset-y-0 left-5 text-gray flex items-center">
<svg 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" class="flex-shrink-0"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
</div>
<input
v-model="form.first_name"
autocapitalize="off"
class="w-full pl-14 h-12 md:h-16 focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border-transparent bg-indigo-100 rounded-md placeholder-gray"
type="text" placeholder="Имя">
</div>
<div v-if="form.errors.email" class="form-error text-sm text-red">{{ form.errors.first_name }}</div>
</div>
<div>
<div class="relative">
<div class="absolute inset-y-0 left-5 text-gray flex items-center">
<svg 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" class="flex-shrink-0">
<path
d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z">
</path>
<polyline points="22,6 12,13 2,6"></polyline>
</svg>
</div>
<input
v-model="form.email"
autocapitalize="off"
class="w-full pl-14 h-12 md:h-16 focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border-transparent bg-indigo-100 rounded-md placeholder-gray"
type="email" placeholder="E-mail">
</div>
<div v-if="form.errors.email" class="form-error text-sm text-red">{{ form.errors.email }}</div>
</div>
<div>
<div class="relative">
<div class="absolute inset-y-0 left-5 text-gray flex items-center">
<svg 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" class="flex-shrink-0">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
</div>
<input
v-model="form.password"
class="w-full pl-14 h-12 md:h-16 focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border-transparent bg-indigo-100 rounded-md placeholder-gray"
type="password" placeholder="Пароль">
</div>
<div v-if="form.errors.password" class="form-error text-sm text-red">{{ form.errors.password }}</div>
</div>
<div class="text-center">
<loading-button :loading="form.processing" class="mx-3 my-1 px-12 py-3 transition shadow-none hover:shadow-classic2 inline-flex items-center justify-center text-base rounded-full text-white bg-orange focus:outline-none" type="submit">Зарегистрироваться</loading-button>
</div>
</form>
</div>
</div>
</div>
<div class="col-span-5 bg-center bg-cover" style="background-image: url('image/orange-auth.jpg');">
<div class="py-4 lg:py-28 px-4 flex flex-col h-full justify-center">
<div class="font-medium text-xl md:text-2xl lg:text-4xl !leading-relaxed text-white text-center">
Уже есть учетная запись?
</div>
<div class="text-center mt-4 md:mt-10">
<inertia-link
:href="route('login')"
class="mx-3 my-1 px-12 py-3 transition shadow-none hover:shadow-classic2 inline-flex items-center justify-center text-base rounded-full text-white border border-white bg-transparent focus:outline-none">
Войти
</inertia-link>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { Inertia } from "@inertiajs/inertia";
import LoadingButton from "@/Shared/Form/LoadingButton";
import MetaHead from '@/Shared/MetaHead'
export default {
components: {
MetaHead,
LoadingButton,
},
setup() {
const form = Inertia.form({
first_name: null,
email: null,
password: null,
});
const submit = () => {
form.post(route("register.store"));
};
return {
form,
submit,
};
},
}
</script>

View File

@@ -0,0 +1,98 @@
<template>
<meta-head title="Новинки"></meta-head>
<div class="mb-6 py-3 md:py-14 xl:py-20 banner relative bg-center bg-no-repeat bg-cover"
style="background-image: url('/image/bg-home.jpg');">
<div class="h-60 lg:h-96 flex justify-center items-center text-center">
<div class="max-w-4xl text-gray px-3">
<p class="text-md md:text-2xl">Социальная сеть для творческих людей</p>
<h1
class="mt-4 md:mt-8 text-xl md:text-2xl lg:text-3xl xl:text-5xl text-white font-semibold xl:leading-relaxed">
Зарабатывай на
своем творчестве вместе с 4Teaser</h1>
<!-- <button type="button"
class="mt-8 inline-flex tracking-wide items-center px-8 md:px-12 py-3 border border-white text-sm lg:text-lg text-white rounded-full bg-transparent hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2">
Присоединиться
</button> -->
</div>
</div>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3 buttons-filter-line">
<div class=" relative mb-5">
<div class="absolute inset-y-0 left-3 flex items-center z-[1]">
<svg class="flex-shrink-0 h-5 w-5 text-gray-light" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" fill="currentColor">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M11 4a7 7 0 100 14 7 7 0 000-14zm-9 7a9 9 0 1118 0 9 9 0 01-18 0z" />
<path fill-rule="evenodd" clip-rule="evenodd"
d="M15.943 15.943a1 1 0 011.414 0l4.35 4.35a1 1 0 01-1.414 1.414l-4.35-4.35a1 1 0 010-1.414z" />
</svg>
</div>
<input
class="relative w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light !pl-10 h-14" placeholder="Поиск"
type="search">
</div>
<div class="grid gap-2 md:gap-5 grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6">
<inertia-link :href="route('dashboard')"
:class="[active_button == 'new' ? 'bg-orange shadow-classic2' : 'shadow-classic bg-indigo-200 hover:bg-orange' , 'transition inline-flex items-center px-3 py-3 lg:px-6 lg:py-6 xl:px-10 text-sm lg:text-lg justify-center rounded-md text-white focus:outline-none']">
Новинки
</inertia-link >
<inertia-link :href="route('dashboard')"
:data="{ filter: 'hot' }"
:class="[active_button == 'hot' ? 'bg-orange shadow-classic2' : 'shadow-classic bg-indigo-200 hover:bg-orange' , 'transition inline-flex items-center px-3 py-3 lg:px-6 lg:py-6 xl:px-10 text-sm lg:text-lg justify-center shadow-classic rounded-md text-white focus:outline-none']">
<svg class="-ml-1 mr-2 h-4 w-4 md:h-5 md:w-5 flex-shrink-0" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
d="M14.422 6.243c-3.57-2.172-1.895-5.238-1.824-5.365A.586.586 0 0012.09 0c-1.837 0-3.276.522-4.276 1.552-1.71 1.76-1.63 4.498-1.597 5.667.004.13.007.242.007.325 0 .868.14 1.67.263 2.377.079.456.147.85.16 1.159.012.331-.048.407-.05.41-.01.01-.081.049-.276.049a.657.657 0 01-.53-.235c-.565-.634-.604-2.365-.496-3.307a.586.586 0 00-.582-.654c-1.521 0-2.658 2.488-2.658 4.712 0 1.046.21 2.07.625 3.045a8.081 8.081 0 001.7 2.527C5.894 19.157 7.89 20 10 20c2.119 0 4.114-.83 5.618-2.34a7.892 7.892 0 002.327-5.605c0-2.692-2.107-4.95-3.523-5.812zM10 18.828c-3.671 0-6.773-3.101-6.773-6.773 0-.893.213-1.83.585-2.571.086-.173.175-.322.263-.447.01.967.163 2.284.841 3.046.366.41.852.627 1.405.627.518 0 .912-.156 1.172-.466.486-.578.337-1.436.148-2.524-.115-.66-.245-1.409-.245-2.176 0-.1-.003-.22-.007-.359-.032-1.107-.099-3.412 1.265-4.817.613-.63 1.467-1.014 2.55-1.145-.123.406-.228.92-.232 1.497-.01 1.27.476 3.085 2.841 4.524 1.145.696 2.96 2.618 2.96 4.811A6.78 6.78 0 0110 18.828z" />
</svg>
Популярные
</inertia-link >
</div>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3 my-6">
<button class="button-default text-gray text-lg">Очистить фильтры</button>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3">
<div class="grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 cards-block rounded-md bg-indigo-200 shadow-classic grid gap-2 lg:gap-4 grid-cards p-2 lg:p-5">
<feed
:self-feed="false"
:feeds="feeds"
/>
</div>
</div>
</template>
<script>
import Feed from "@/Shared/Feed/Feed";
import Layout from '@/Shared/Layout'
import MetaHead from '@/Shared/MetaHead'
export default {
layout: Layout,
components: {
MetaHead,
Feed
},
props: {
feeds: Array,
active_button: String,
},
methods: {
},
}
</script>

View File

@@ -0,0 +1,99 @@
<template>
<meta-head title="Новости"></meta-head>
<div class="mt-16 container mx-auto px-2 md:px-6 2xl:px-28 buttons-filter-line">
<div class="items-center grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-4 2xl:gap-12">
<dropdown-menu>
<MenuItems class="origin-top-left absolute left-0 mt-2 w-64 bg-indigo-300 shadow-lg max-h-60 rounded-md text-base ring-1 ring-indigo-200 overflow-auto focus:outline-none">
<MenuItem>
<inertia-link :href="route('video.create')" class="group flex items-center px-4 py-2 text-base hover:bg-indigo-200 text-gray-light">
<VideoCameraIcon class="mr-3 h-5 w-5 text-gray-400 group-hover:text-orange" aria-hidden="true" />
Загрузить видео
</inertia-link>
</MenuItem>
<MenuItem>
<inertia-link :href="route('image.create')" class="group flex items-center px-4 py-2 text-base hover:bg-indigo-200 text-gray-light">
<PhotographIcon class="mr-3 h-5 w-5 text-gray-400 group-hover:text-orange" aria-hidden="true" />
Загрузить изображение
</inertia-link>
</MenuItem>
<MenuItem>
<inertia-link :href="route('music.create')" class="group flex items-center px-4 py-2 text-base hover:bg-indigo-200 text-gray-light">
<MusicNoteIcon class="mr-3 h-5 w-5 text-gray-400 group-hover:text-orange" aria-hidden="true" />
Загрузить музыку
</inertia-link>
</MenuItem>
</MenuItems>
</dropdown-menu>
<inertia-link
:href='route("feeds.layoutsidebar.image")'
:class="[active_button == 'image' ? 'bg-orange' : 'bg-indigo-200 hover:bg-orange', 'transition inline-flex items-center px-3 py-3 lg:px-7 lg:py-5 justify-center shadow-classic text-sm rounded-md text-white focus:outline-none']">
<svg class="-ml-1 mr-2 h-4 w-4 md:h-5 md:w-5 flex-shrink-0" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M4.167 3.333a.833.833 0 00-.834.834v11.666c0 .46.373.834.834.834h11.666c.46 0 .834-.373.834-.834V4.167a.833.833 0 00-.834-.834H4.167zm-2.5.834a2.5 2.5 0 012.5-2.5h11.666a2.5 2.5 0 012.5 2.5v11.666a2.5 2.5 0 01-2.5 2.5H4.167a2.5 2.5 0 01-2.5-2.5V4.167z" />
<path fill-rule="evenodd" clip-rule="evenodd"
d="M7.083 6.667a.417.417 0 100 .833.417.417 0 000-.833zM5 7.083a2.083 2.083 0 114.167 0 2.083 2.083 0 01-4.167 0zM12.744 7.744a.833.833 0 011.179 0l4.166 4.167a.834.834 0 01-1.178 1.178l-3.578-3.577-8.577 8.577a.833.833 0 01-1.179-1.178l9.167-9.167z" />
</svg>
<span class="truncate">Изображения</span>
</inertia-link>
<inertia-link
:href='route("feeds.layoutsidebar.video")'
:class="[active_button == 'video' ? 'bg-orange' : 'bg-indigo-200 hover:bg-orange' , 'transition inline-flex items-center px-3 py-3 lg:px-7 lg:py-5 justify-center shadow-classic text-sm rounded-md text-white focus:outline-none']">
<svg class="-ml-1 mr-2 h-4 w-4 md:h-5 md:w-5 flex-shrink-0" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" clip-rule="evenodd" d="M3.483 2.5a.983.983 0 00-.983.983v13.034c0 .543.44.983.983.983h13.034c.543 0 .983-.44.983-.983V3.483a.983.983 0 00-.983-.983H3.483zm-2.65.983a2.65 2.65 0 012.65-2.65h13.034a2.65 2.65 0 012.65 2.65v13.034a2.65 2.65 0 01-2.65 2.65H3.483a2.65 2.65 0 01-2.65-2.65V3.483z" /><path fill-rule="evenodd" clip-rule="evenodd" d="M5.833.833c.46 0 .834.373.834.834v16.666a.833.833 0 11-1.667 0V1.667c0-.46.373-.834.833-.834zM14.167.833c.46 0 .833.373.833.834v16.666a.833.833 0 11-1.667 0V1.667c0-.46.373-.834.834-.834z" /><path fill-rule="evenodd" clip-rule="evenodd" d="M.833 10c0-.46.373-.833.834-.833h16.666a.833.833 0 010 1.666H1.667A.833.833 0 01.833 10zM.833 5.833c0-.46.373-.833.834-.833h4.166a.833.833 0 010 1.667H1.667a.833.833 0 01-.834-.834zM.833 14.167c0-.46.373-.834.834-.834h4.166a.833.833 0 010 1.667H1.667a.833.833 0 01-.834-.833zM13.333 14.167c0-.46.373-.834.834-.834h4.166a.833.833 0 010 1.667h-4.166a.833.833 0 01-.834-.833zM13.333 5.833c0-.46.373-.833.834-.833h4.166a.833.833 0 010 1.667h-4.166a.833.833 0 01-.834-.834z" /></svg>
<span class="truncate">Видео</span>
</inertia-link>
<inertia-link
:href='route("feeds.layoutsidebar.music")'
:class="[active_button == 'music' ? 'bg-orange' : 'bg-indigo-200 hover:bg-orange' , 'transition inline-flex items-center px-3 py-3 lg:px-7 lg:py-5 justify-center shadow-classic text-sm rounded-md text-white focus:outline-none']">
<svg class="-ml-1 mr-2 h-4 w-4 md:h-5 md:w-5 flex-shrink-0" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.399 12.399a2.5 2.5 0 011.768-.732H17.5c.46 0 .833.373.833.833v1.667a2.5 2.5 0 01-2.5 2.5h-1.666a2.5 2.5 0 01-1.768-4.268zm1.768.934a.833.833 0 000 1.667h1.666a.833.833 0 00.834-.833v-.834h-2.5zm-11.768.733a2.5 2.5 0 011.768-.733H7.5c.46 0 .833.373.833.834v1.666a2.5 2.5 0 01-2.5 2.5H4.167a2.5 2.5 0 01-1.768-4.267zM4.167 15a.833.833 0 100 1.667h1.666a.833.833 0 00.834-.834V15h-2.5z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M18.039 1.864c.187.158.294.391.294.636v10a.833.833 0 01-1.666 0V3.484L8.333 4.873v9.294a.833.833 0 01-1.666 0v-10c0-.408.294-.755.696-.822l10-1.667a.833.833 0 01.676.186z"/></svg>
<span class="truncate">Музыка</span>
</inertia-link>
</div>
</div>
<div class="feeds-user-list mt-5 container mx-auto px-2 md:px-6 2xl:px-28 space-y-4 lg:space-y-8">
<feed-list
:self-feed="false"
:feeds="feeds"
/>
</div>
</template>
<script>
import FeedList from "@/Shared/FeedList/FeedList";
import Layout from '@/Shared/Layout'
import MetaHead from '@/Shared/MetaHead'
import {
PhotographIcon,
VideoCameraIcon,
MusicNoteIcon,
} from '@heroicons/vue/solid'
import { MenuItem, MenuItems } from '@headlessui/vue'
import DropdownMenu from '@/Shared/Form/DropdownMenu'
export default {
components: {
FeedList,
MetaHead,
DropdownMenu,
MenuItem,
MenuItems,
PhotographIcon,
MusicNoteIcon,
VideoCameraIcon
},
layout: Layout,
props: {
feeds: Array,
active_button: String,
},
}
</script>

View File

@@ -0,0 +1,128 @@
<template>
<meta-head title="Загрузить изображение"></meta-head>
<div class="mt-16 container mx-auto px-2 md:px-6 2xl:px-28 buttons-filter-line">
<form @submit.prevent="submit" class=" bg-indigo-200 shadow-classic rounded-md p-5">
<div class="mb-4 flex items-center text-gray-light text-lg font-medium">
<inertia-link :href="route('profile.user', $page.props.auth.user.username)" class="block hover:underline">
Вернуться
</inertia-link>
<span class="px-3">/</span>
<h1 class="text-gray">Загрузка изображения</h1>
</div>
<div class="space-y-5">
<div class="flex flex-col">
<text-input v-model="form.title" :error="form.errors.title" type="text" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light" label="Название" />
</div>
<div class="flex flex-col">
<textarea-input v-model="form.body" :error="form.errors.body" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md" cols="30" rows="4" label="Описание" />
</div>
<div class="flex flex-col">
<file-input-multiple
v-model="form.photos"
:error="form.errors.photos"
label="Выбрать изображения"
/>
</div>
<div class="text-gray-light">
<input class="w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md" placeholder="#tags" type="text">
</div>
<div>
<div class="text-gray-light text-lg mb-2">Тип контента</div>
<div class="flex space-x-6">
<div class="flex items-center">
<input id="feed-paid-1" v-model="paid" value="0" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="feed-paid-1" class="select-none ml-3 text-gray">Бесплатный</label>
</div>
<div class="flex items-center">
<input id="feed-paid-2" v-model="paid" value="1" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="feed-paid-2" class="select-none ml-3 text-gray">Платный</label>
</div>
</div>
</div>
<div class="space-y-5" v-if="contentPaid == 1">
<div class="flex flex-col">
<text-input v-model="form.price" :error="form.errors.price" type="number" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light" label="Цена" />
</div>
<div class="flex flex-col">
<file-input-multiple
v-model="form.photos_paid"
:error="form.errors.photos_paid"
label="Выбрать изображения"
/>
</div>
</div>
</div>
<div class="mt-12 flex flex-wrap -my-1 -mx-3">
<progress
class="mx-3 my-1 w-full"
v-if="form.progress"
:value="form.progress.percentage"
max="100"
>
{{ form.progress.percentage }}%
</progress>
<loading-button :loading="form.processing" class="mx-3 my-1 transition shadow-none hover:shadow-classic2 inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-orange focus:outline-none" type="submit">
Создать
</loading-button>
<button type="button"
class="mx-3 my-1 transition shadow-none hover:shadow-classic inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-indigo-300 focus:outline-none">
Отменить
</button>
</div>
</form>
</div>
</template>
<script>
import Layout from '@/Shared/Layout'
import MetaHead from '@/Shared/MetaHead'
import TextInput from '@/Shared/Form/TextInput'
import FileInputMultiple from '@/Shared/Form/FileInputMultiple'
import TextareaInput from '@/Shared/Form/TextareaInput'
import LoadingButton from "@/Shared/Form/LoadingButton";
import { useForm } from "@inertiajs/inertia-vue3";
export default {
components: {
MetaHead,
TextInput,
FileInputMultiple,
LoadingButton,
TextareaInput,
},
layout: Layout,
data(){
return {
paid: 0,
contentPaid: 0,
}
},
watch:{
paid(value){
this.contentPaid = value;
this.form.is_paid = value;
}
},
setup() {
const form = useForm({
title: null,
body: null,
price: null,
photos: null,
photos_paid: null,
is_paid: 0
});
const submit = () => {
form.post(route("image.store"));
};
return { form, submit }
},
}
</script>

View File

@@ -0,0 +1,97 @@
<template>
<meta-head title="Изображения"></meta-head>
<div class="mb-6 py-3 banner relative bg-center bg-no-repeat bg-cover"
style="background-image: url('/image/bg-home.jpg');">
<div class="h-52 flex justify-center items-center text-center">
<div class="max-w-4xl text-gray px-3">
<h1
class=" text-xl md:text-2xl lg:text-3xl xl:text-5xl text-white font-semibold xl:leading-relaxed">
Изображения</h1>
<inertia-link :href="route('image.create')"
class="mt-8 inline-flex tracking-wide items-center px-8 md:px-12 py-3 border border-white text-sm lg:text-lg text-white rounded-full bg-transparent hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2">
Загрузить
</inertia-link>
</div>
</div>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3 buttons-filter-line">
<div class=" relative mb-5">
<div class="absolute inset-y-0 left-3 flex items-center z-[1]">
<svg class="flex-shrink-0 h-5 w-5 text-gray-light" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" fill="currentColor">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M11 4a7 7 0 100 14 7 7 0 000-14zm-9 7a9 9 0 1118 0 9 9 0 01-18 0z" />
<path fill-rule="evenodd" clip-rule="evenodd"
d="M15.943 15.943a1 1 0 011.414 0l4.35 4.35a1 1 0 01-1.414 1.414l-4.35-4.35a1 1 0 010-1.414z" />
</svg>
</div>
<input
class="relative w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light !pl-10 h-14" placeholder="Поиск"
type="search">
</div>
<div class="grid gap-2 md:gap-5 grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6">
<inertia-link :href="route('list.images')"
:class="[active_button == 'new' ? 'bg-orange shadow-classic2' : 'shadow-classic bg-indigo-200 hover:bg-orange' , 'transition inline-flex items-center px-3 py-3 lg:px-6 lg:py-6 xl:px-10 text-sm lg:text-lg justify-center rounded-md text-white focus:outline-none']">
Новинки
</inertia-link >
<inertia-link :href="route('list.images')"
:data="{ filter: 'hot' }"
:class="[active_button == 'hot' ? 'bg-orange shadow-classic2' : 'shadow-classic bg-indigo-200 hover:bg-orange' , 'transition inline-flex items-center px-3 py-3 lg:px-6 lg:py-6 xl:px-10 text-sm lg:text-lg justify-center shadow-classic rounded-md text-white focus:outline-none']">
<svg class="-ml-1 mr-2 h-4 w-4 md:h-5 md:w-5 flex-shrink-0" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
d="M14.422 6.243c-3.57-2.172-1.895-5.238-1.824-5.365A.586.586 0 0012.09 0c-1.837 0-3.276.522-4.276 1.552-1.71 1.76-1.63 4.498-1.597 5.667.004.13.007.242.007.325 0 .868.14 1.67.263 2.377.079.456.147.85.16 1.159.012.331-.048.407-.05.41-.01.01-.081.049-.276.049a.657.657 0 01-.53-.235c-.565-.634-.604-2.365-.496-3.307a.586.586 0 00-.582-.654c-1.521 0-2.658 2.488-2.658 4.712 0 1.046.21 2.07.625 3.045a8.081 8.081 0 001.7 2.527C5.894 19.157 7.89 20 10 20c2.119 0 4.114-.83 5.618-2.34a7.892 7.892 0 002.327-5.605c0-2.692-2.107-4.95-3.523-5.812zM10 18.828c-3.671 0-6.773-3.101-6.773-6.773 0-.893.213-1.83.585-2.571.086-.173.175-.322.263-.447.01.967.163 2.284.841 3.046.366.41.852.627 1.405.627.518 0 .912-.156 1.172-.466.486-.578.337-1.436.148-2.524-.115-.66-.245-1.409-.245-2.176 0-.1-.003-.22-.007-.359-.032-1.107-.099-3.412 1.265-4.817.613-.63 1.467-1.014 2.55-1.145-.123.406-.228.92-.232 1.497-.01 1.27.476 3.085 2.841 4.524 1.145.696 2.96 2.618 2.96 4.811A6.78 6.78 0 0110 18.828z" />
</svg>
Популярные
</inertia-link >
</div>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3 my-6">
<button class="button-default text-gray text-lg">Очистить фильтры</button>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3">
<div class="grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 cards-block rounded-md bg-indigo-200 shadow-classic grid gap-2 lg:gap-4 grid-cards p-2 lg:p-5">
<feed
:self-feed="false"
:feeds="feeds"
/>
</div>
</div>
</template>
<script>
import Feed from "@/Shared/Feed/Feed";
import Layout from '@/Shared/Layout'
import MetaHead from '@/Shared/MetaHead'
export default {
layout: Layout,
components: {
MetaHead,
Feed
},
props: {
feeds: Array,
active_button: String,
},
methods: {
},
}
</script>

View File

@@ -0,0 +1,159 @@
<template>
<meta-head title="Загрузить музыку"></meta-head>
<div class="mt-16 container mx-auto px-2 md:px-6 2xl:px-28 buttons-filter-line">
<form @submit.prevent="submit" class=" bg-indigo-200 shadow-classic rounded-md p-5">
<div class="mb-4 flex items-center text-gray-light text-lg font-medium">
<inertia-link :href="route('profile.user', $page.props.auth.user.username)" class="block hover:underline">
Вернуться
</inertia-link>
<span class="px-3">/</span>
<h1 class="text-gray">Загрузка музыки</h1>
</div>
<div class="space-y-5">
<div class="flex flex-col">
<text-input v-model="form.title" :error="form.errors.title" type="text" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light" label="Название" />
</div>
<div class="flex flex-col">
<textarea-input v-model="form.body" :error="form.errors.body" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md" cols="30" rows="4" label="Описание" />
</div>
<div class="flex flex-col">
<file-input
v-model="form.preview"
accept="image/png, image/jpeg, image/jpg"
:error="form.errors.preview"
label="Загрузить превью"
/>
</div>
<div class="flex flex-col">
<file-input-multiple
@fileTime='saveTimeFile'
v-model="form.musics"
accept=".mp3"
:error="form.errors.musics"
label="Выбрать музыку"
/>
</div>
<div class="text-gray-light">
<input class="w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md" placeholder="#tags" type="text">
</div>
<div>
<div class="text-gray-light text-lg mb-2">Тип контента</div>
<div class="flex space-x-6">
<div class="flex items-center">
<input id="feed-paid-1" v-model="paid" value="0" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="feed-paid-1" class="select-none ml-3 text-gray">Бесплатный</label>
</div>
<div class="flex items-center">
<input id="feed-paid-2" v-model="paid" value="1" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="feed-paid-2" class="select-none ml-3 text-gray">Платный</label>
</div>
</div>
</div>
<div class="space-y-5" v-if="contentPaid == 1">
<div class="flex flex-col">
<text-input v-model="form.price" :error="form.errors.price" type="number" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light" label="Цена" />
</div>
<div class="flex flex-col">
<file-input-multiple
@fileTime='savePaidTimeFile'
v-model="form.musics_paid"
accept=".mp3"
:error="form.errors.musics_paid"
label="Выбрать музыку"
/>
</div>
</div>
</div>
<div class="mt-12 flex flex-wrap -my-1 -mx-3">
<progress
class="mx-3 my-1 w-full"
v-if="form.progress"
:value="form.progress.percentage"
max="100"
>
{{ form.progress.percentage }}%
</progress>
<loading-button :loading="form.processing" class="mx-3 my-1 transition shadow-none hover:shadow-classic2 inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-orange focus:outline-none" type="submit">
Создать
</loading-button>
<button type="button"
class="mx-3 my-1 transition shadow-none hover:shadow-classic inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-indigo-300 focus:outline-none">
Отменить
</button>
</div>
</form>
</div>
</template>
<script>
import Layout from "@/Shared/Layout";
import MetaHead from "@/Shared/MetaHead";
import TextInput from "@/Shared/Form/TextInput";
import FileInputMultiple from "@/Shared/Form/FileInputMultiple";
import FileInput from "@/Shared/Form/FileInput";
import TextareaInput from "@/Shared/Form/TextareaInput";
import LoadingButton from "@/Shared/Form/LoadingButton";
import { useForm } from "@inertiajs/inertia-vue3";
export default {
layout: Layout,
components: {
MetaHead,
TextInput,
FileInput,
FileInputMultiple,
LoadingButton,
TextareaInput,
},
watch: {
paid(value) {
this.contentPaid = value;
this.form.is_paid = value;
},
},
data() {
return {
paid: 0,
contentPaid: 0,
};
},
setup() {
const form = useForm({
title: null,
body: null,
preview: null,
musics: null,
musics_paid: null,
price: null,
is_paid: 0,
times: [],
times_paid: [],
});
const submit = () => {
form.post(route("music.store"));
};
const saveTimeFile = (time) => {
form.times.push(time);
};
const savePaidTimeFile = (time) => {
form.times_paid.push(time);
};
return { form, submit, saveTimeFile, savePaidTimeFile };
},
};
</script>

View File

@@ -0,0 +1,97 @@
<template>
<meta-head title="Музыка"></meta-head>
<div class="mb-6 py-3 banner relative bg-center bg-no-repeat bg-cover"
style="background-image: url('/image/bg-home.jpg');">
<div class="h-52 flex justify-center items-center text-center">
<div class="max-w-4xl text-gray px-3">
<h1
class=" text-xl md:text-2xl lg:text-3xl xl:text-5xl text-white font-semibold xl:leading-relaxed">
Музыка</h1>
<inertia-link :href="route('music.create')"
class="mt-8 inline-flex tracking-wide items-center px-8 md:px-12 py-3 border border-white text-sm lg:text-lg text-white rounded-full bg-transparent hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2">
Загрузить
</inertia-link>
</div>
</div>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3 buttons-filter-line">
<div class=" relative mb-5">
<div class="absolute inset-y-0 left-3 flex items-center z-[1]">
<svg class="flex-shrink-0 h-5 w-5 text-gray-light" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" fill="currentColor">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M11 4a7 7 0 100 14 7 7 0 000-14zm-9 7a9 9 0 1118 0 9 9 0 01-18 0z" />
<path fill-rule="evenodd" clip-rule="evenodd"
d="M15.943 15.943a1 1 0 011.414 0l4.35 4.35a1 1 0 01-1.414 1.414l-4.35-4.35a1 1 0 010-1.414z" />
</svg>
</div>
<input
class="relative w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light !pl-10 h-14" placeholder="Поиск"
type="search">
</div>
<div class="grid gap-2 md:gap-5 grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6">
<inertia-link :href="route('list.musics')"
:class="[active_button == 'new' ? 'bg-orange shadow-classic2' : 'shadow-classic bg-indigo-200 hover:bg-orange' , 'transition inline-flex items-center px-3 py-3 lg:px-6 lg:py-6 xl:px-10 text-sm lg:text-lg justify-center rounded-md text-white focus:outline-none']">
Новинки
</inertia-link >
<inertia-link :href="route('list.musics')"
:data="{ filter: 'hot' }"
:class="[active_button == 'hot' ? 'bg-orange shadow-classic2' : 'shadow-classic bg-indigo-200 hover:bg-orange' , 'transition inline-flex items-center px-3 py-3 lg:px-6 lg:py-6 xl:px-10 text-sm lg:text-lg justify-center shadow-classic rounded-md text-white focus:outline-none']">
<svg class="-ml-1 mr-2 h-4 w-4 md:h-5 md:w-5 flex-shrink-0" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
d="M14.422 6.243c-3.57-2.172-1.895-5.238-1.824-5.365A.586.586 0 0012.09 0c-1.837 0-3.276.522-4.276 1.552-1.71 1.76-1.63 4.498-1.597 5.667.004.13.007.242.007.325 0 .868.14 1.67.263 2.377.079.456.147.85.16 1.159.012.331-.048.407-.05.41-.01.01-.081.049-.276.049a.657.657 0 01-.53-.235c-.565-.634-.604-2.365-.496-3.307a.586.586 0 00-.582-.654c-1.521 0-2.658 2.488-2.658 4.712 0 1.046.21 2.07.625 3.045a8.081 8.081 0 001.7 2.527C5.894 19.157 7.89 20 10 20c2.119 0 4.114-.83 5.618-2.34a7.892 7.892 0 002.327-5.605c0-2.692-2.107-4.95-3.523-5.812zM10 18.828c-3.671 0-6.773-3.101-6.773-6.773 0-.893.213-1.83.585-2.571.086-.173.175-.322.263-.447.01.967.163 2.284.841 3.046.366.41.852.627 1.405.627.518 0 .912-.156 1.172-.466.486-.578.337-1.436.148-2.524-.115-.66-.245-1.409-.245-2.176 0-.1-.003-.22-.007-.359-.032-1.107-.099-3.412 1.265-4.817.613-.63 1.467-1.014 2.55-1.145-.123.406-.228.92-.232 1.497-.01 1.27.476 3.085 2.841 4.524 1.145.696 2.96 2.618 2.96 4.811A6.78 6.78 0 0110 18.828z" />
</svg>
Популярные
</inertia-link >
</div>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3 my-6">
<button class="button-default text-gray text-lg">Очистить фильтры</button>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3">
<div class="grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 cards-block rounded-md bg-indigo-200 shadow-classic grid gap-2 lg:gap-4 grid-cards p-2 lg:p-5">
<feed
:self-feed="false"
:feeds="feeds"
/>
</div>
</div>
</template>
<script>
import Feed from "@/Shared/Feed/Feed";
import Layout from '@/Shared/Layout'
import MetaHead from '@/Shared/MetaHead'
export default {
layout: Layout,
components: {
MetaHead,
Feed
},
props: {
feeds: Array,
active_button: String,
},
methods: {
},
}
</script>

View File

@@ -0,0 +1,45 @@
<template>
<meta-head title="Профиль юзера"></meta-head>
<profile-header :user='user' :counts='counts' />
<profile-menu :user='user' />
<div class="mt-12 xl:container xl:mx-auto px-2 md:px-3">
<div class="grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 cards-block rounded-md bg-indigo-200 shadow-classic grid gap-2 lg:gap-4 grid-cards p-2 lg:p-5">
<feed
:self-user="user.id"
:self-feed="true"
:feeds="feeds"
/>
</div>
</div>
</template>
<script>
import Layout from '@/Shared/Layout'
import MetaHead from '@/Shared/MetaHead'
import ProfileHeader from '@/Shared/Partials/ProfileHeader'
import ProfileMenu from '@/Shared/Partials/ProfileMenu'
import Feed from "@/Shared/Feed/Feed";
export default {
layout: Layout,
components: {
Feed,
MetaHead,
ProfileHeader,
ProfileMenu,
},
props: {
user: Object,
feeds: Array,
counts: Object,
}
}
</script>

View File

@@ -0,0 +1,155 @@
<template>
<meta-head title="Читаемые пользователи"></meta-head>
<profile-header :user='user' :counts='counts' />
<profile-menu :user='user' />
<div class="mt-12 xl:container xl:mx-auto px-2 md:px-3">
<div class="cards-block rounded-md bg-indigo-200 shadow-classic p-2 lg:p-5">
<div class=" space-y-3 md:space-y-0 md:flex items-center">
<div class="flex-1 md:mr-10">
<div class="relative">
<div class="absolute inset-y-0 left-3 flex items-center z-10">
<svg class="flex-shrink-0 h-5 w-5 text-gray-light" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" > <path fill-rule="evenodd" clip-rule="evenodd" d="M11 4a7 7 0 100 14 7 7 0 000-14zm-9 7a9 9 0 1118 0 9 9 0 01-18 0z"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M15.943 15.943a1 1 0 011.414 0l4.35 4.35a1 1 0 01-1.414 1.414l-4.35-4.35a1 1 0 010-1.414z"/> </svg>
</div>
<input v-model="form.search" class=" relative w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light !pl-10 " placeholder="Поиск" type="search"/>
</div>
</div>
<div class="flex space-x-6 md:mr-10">
<div class="flex items-center">
<input id="user-sex-1" v-model="form.leader" value="1" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="user-sex-1" class="select-none ml-3 text-gray text-xs md:text-base">По лидерам</label>
</div>
<div class="flex items-center">
<input id="user-sex-2" v-model="form.leader" value="0" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="user-sex-2" class="select-none ml-3 text-gray text-xs md:text-base">Не по лидерам</label>
</div>
</div>
<div class="text-gray-light">
<button @click="resetSearch()" class="default">Сбросить</button>
</div>
</div>
<div v-show="readers.length" class="mt-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 grid gap-2 lg:gap-4 grid-cards">
<div v-for="reader in readers" :key='reader.id' class="group mb-5 user-card relative">
<div v-if="user.is_auth_user" class="absolute inset-x-0 top-4 z-10 flex justify-center">
<toggle
@clicked='leader'
:user_id='reader.id'
:enabled="reader.is_leader"
textin='Сделать лидером' textout='Убрать лидера' />
</div>
<div class="absolute inset-x-0 bottom-4 z-10 flex justify-center">
<div class="flex flex-col items-center">
<inertia-link :href="route('profile.user', reader.username)" class="block flex-shrink-0">
<user-avatar :user='reader' size='small' class="border border-white shadow-classic h-20 w-20 text-lg" />
</inertia-link>
<inertia-link :href="route('profile.user', reader.username)" class="mt-2 block text-white text-sm text-center">
<p>{{reader.name}}</p>
<p class="text-xs">{{reader.username}}</p>
</inertia-link>
</div>
</div>
<div class="gradient-profile relative overflow-hidden">
<user-banner class="w-full h-72 bg-indigo-300" :user='reader' size='banner' />
</div>
<div v-if="user.is_auth_user" class="transition-opacity sm:opacity-0 group-hover:opacity-100 absolute w-full text-center">
<button @click="susbscribe(reader.id)" class="leading-none focus:outline-none hover:underline text-sm text-orange-dark">Отписаться</button>
</div>
</div>
</div>
</div>
<div v-show="readers.length == 0">
<p class=" text-center md:text-2xl text-gray-light">Пользователи не найдены</p>
</div>
</div>
</template>
<script>
import Layout from '@/Shared/Layout'
import MetaHead from '@/Shared/MetaHead'
import ProfileHeader from '@/Shared/Partials/ProfileHeader'
import ProfileMenu from '@/Shared/Partials/ProfileMenu'
import UserAvatar from '@/Shared/Misc/UserAvatar'
import UserBanner from '@/Shared/Misc/UserBanner'
import Toggle from '@/Shared/Form/Toggle'
import filter from 'lodash/filter';
import pickBy from 'lodash/pickBy';
import throttle from 'lodash/throttle';
import { Inertia } from "@inertiajs/inertia";
export default {
layout: Layout,
components: {
MetaHead,
Toggle,
UserAvatar,
UserBanner,
ProfileHeader,
ProfileMenu,
},
props: {
user: Object,
readers: Array,
counts: Object,
filters: Object,
},
data() {
return {
form: {
search: this.filters.search,
leader: this.filters.leader,
},
}
},
watch: {
form: {
handler: throttle(function() {
let query = pickBy(this.form)
const params = Object.keys(query).length ? query : { remember: 'forget' };
const url = route('profile.readers', this.user.username);
Inertia.get(url, params, { replace: true, preserveScroll: true, preserveState: true } )
}, 300),
deep: true,
},
},
methods:{
resetSearch(){
this.form.search = '';
this.form.leader = '';
},
susbscribe(user_id)
{
Inertia.post(route('users.subs', user_id), {}, { preserveScroll: true, preserveState: true })
},
leader(user_id)
{
let current_user = filter(this.readers, function (x) {
return x.id === user_id;
});
if(current_user){
current_user = current_user[0];
Inertia.post(route('users.leader', user_id), {vote: current_user.is_leader}, { preserveScroll: true, preserveState: true })
}
}
}
}
</script>

View File

@@ -0,0 +1,136 @@
<template>
<meta-head title="Подписчики"></meta-head>
<profile-header :user='user' :counts='counts' />
<profile-menu :user='user' />
<div class="mt-12 xl:container xl:mx-auto px-2 md:px-3">
<div class="cards-block rounded-md bg-indigo-200 shadow-classic p-2 lg:p-5">
<div class=" space-y-3 md:space-y-0 md:flex items-center">
<div class="flex-1 md:mr-10">
<div class="relative">
<div class="absolute inset-y-0 left-3 flex items-center z-10">
<svg class="flex-shrink-0 h-5 w-5 text-gray-light" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" > <path fill-rule="evenodd" clip-rule="evenodd" d="M11 4a7 7 0 100 14 7 7 0 000-14zm-9 7a9 9 0 1118 0 9 9 0 01-18 0z"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M15.943 15.943a1 1 0 011.414 0l4.35 4.35a1 1 0 01-1.414 1.414l-4.35-4.35a1 1 0 010-1.414z"/> </svg>
</div>
<input v-model="form.search" class=" relative w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light !pl-10 " placeholder="Поиск" type="search"/>
</div>
</div>
<div class="flex space-x-6 md:mr-10">
<div class="flex items-center">
<input id="user-sex-1" v-model="form.sub" value="1" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="user-sex-1" class="select-none ml-3 text-gray text-xs md:text-base">По подписчикам</label>
</div>
<div class="flex items-center">
<input id="user-sex-2" v-model="form.sub" value="0" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="user-sex-2" class="select-none ml-3 text-gray text-xs md:text-base">Не по подписчикам</label>
</div>
</div>
<div class="text-gray-light">
<button @click="resetSearch()" class="default">Сбросить</button>
</div>
</div>
<div v-show="subscribers.length" class="mt-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 grid gap-2 lg:gap-4 grid-cards">
<div v-for="subscriber in subscribers" :key='subscriber.id' class=" user-card relative">
<div v-if="user.is_auth_user" class="absolute inset-x-0 top-4 z-10 flex justify-center">
<toggle
@clicked='susbscribe'
:user_id='subscriber.id'
:enabled="subscriber.is_sub"
textin='Подписаться' textout='Отписаться' />
</div>
<div class="absolute inset-x-0 bottom-4 z-10 flex justify-center">
<div class="flex flex-col items-center">
<inertia-link :href="route('profile.user', subscriber.username)" class="block flex-shrink-0">
<user-avatar :user='subscriber' size='small' class="border border-white shadow-classic h-20 w-20 text-lg" />
</inertia-link>
<inertia-link :href="route('profile.user', subscriber.username)" class="mt-2 block text-white text-sm text-center">
<p>{{subscriber.name}}</p>
<p class="text-xs">{{subscriber.username}}</p>
</inertia-link>
</div>
</div>
<div class="gradient-profile relative overflow-hidden">
<user-banner class="w-full h-72 bg-indigo-300" :user='subscriber' size='banner' />
</div>
</div>
</div>
</div>
<div v-show="subscribers.length == 0">
<p class=" text-center md:text-2xl text-gray-light">Пользователи не найдены</p>
</div>
</div>
</template>
<script>
import Layout from '@/Shared/Layout'
import MetaHead from '@/Shared/MetaHead'
import ProfileHeader from '@/Shared/Partials/ProfileHeader'
import ProfileMenu from '@/Shared/Partials/ProfileMenu'
import UserAvatar from '@/Shared/Misc/UserAvatar'
import UserBanner from '@/Shared/Misc/UserBanner'
import Toggle from '@/Shared/Form/Toggle'
import pickBy from 'lodash/pickBy';
import throttle from 'lodash/throttle';
import { Inertia } from "@inertiajs/inertia";
export default {
layout: Layout,
components: {
MetaHead,
Toggle,
UserAvatar,
UserBanner,
ProfileHeader,
ProfileMenu,
},
props: {
user: Object,
subscribers: Array,
counts: Object,
filters: Object,
},
data() {
return {
form: {
search: this.filters.search,
sub: this.filters.sub,
},
}
},
watch: {
form: {
handler: throttle(function() {
let query = pickBy(this.form)
const params = Object.keys(query).length ? query : { remember: 'forget' };
const url = route('profile.subs', this.user.username);
Inertia.get(url, params, { replace: true, preserveScroll: true, preserveState: true } )
}, 300),
deep: true,
},
},
methods:{
resetSearch(){
this.form.search = '';
this.form.sub = '';
},
susbscribe(user_id)
{
Inertia.post(route('users.subs', user_id), {}, { preserveScroll: true, preserveState: true })
},
}
}
</script>

View File

@@ -0,0 +1,84 @@
<template>
<meta-head title="Доход"></meta-head>
<div class="xl:container xl:mx-auto px-2 md:px-3">
<div class="mt-16 shadow-classic rounded-md bg-indigo-200">
<div class="flex flex-col md:grid grid-cols-6 lg:grid-cols-5">
<settings-menu />
<div class="col-span-4">
<div class="border-b border-indigo-300">
<div class="flex justify-between px-4 2xl:px-28 my-4 lg:my-8">
<div class="flex flex-col text-white">
<span class="text-lg">Баланс:</span>
<span class="text-3xl">{{$page.props.balance}}</span>
</div>
<button @click="testPaid" type="button"
class="my-1 transition shadow-none hover:shadow-classic2 inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-pink focus:outline-none">
Пополнить
</button>
<button type="button"
class="my-1 transition shadow-none hover:shadow-classic2 inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-orange focus:outline-none">
Вывести
</button>
</div>
</div>
<div class="my-4 lg:my-8">
<div class="py-4 px-4 2xl:px-28 md:text-lg text-white">История операций:</div>
<div class="divide-y divide-indigo-300 ">
<div v-for="point in points" :key="point.id" class="py-4 px-4 2xl:px-28 lg:items-center flex flex-col lg:grid gap-2 lg:gap-5 grid-cols-12">
<div class="col-span-5 flex items-center">
<div class="flex-shrink-0 mr-3 lg:mr-8">
<svg :class="[point.direction == 0 ? 'text-green rotate-90' : '-rotate-90 text-red', 'transform w-8 h-8']">
<use xlink:href="#arrow-up-circle"></use>
</svg>
</div>
<div class="flex flex-col">
<p class="truncate text-base lg:text-lg font-semibold text-gray">{{point.date}}</p>
<p class="truncate lg:mt-1 text-base text-gray-light">{{point.time}}</p>
</div>
</div>
<div class="col-span-2 text-left lg:text-center text-white xl:text-xl font-semibold">
{{point.point}}
</div>
<div class="col-span-5 text-left lg:text-right text-gray-light xl:text-lg">
{{point.type}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { Inertia } from "@inertiajs/inertia";
import Layout from '@/Shared/Layout'
import SettingsMenu from '@/Shared/LayoutParts/SettingsMenu'
import MetaHead from '@/Shared/MetaHead'
export default {
layout: Layout,
components: {
MetaHead,
SettingsMenu,
},
props:{
points: Array,
},
methods: {
testPaid(){
Inertia.post(route("users.testPaid"), {
preserveScroll: true,
preserveState: true,
});
}
},
}
</script>

View File

@@ -0,0 +1,128 @@
<template>
<meta-head title="Оповещения"></meta-head>
<div class="xl:container xl:mx-auto px-2 md:px-3">
<div class="mt-16 shadow-classic rounded-md bg-indigo-200">
<div class="flex flex-col md:grid grid-cols-6 lg:grid-cols-5">
<settings-menu />
<div class="col-span-4">
<div data-simplebar class="max-h-[500px] overflow-auto my-4 lg:my-8">
<div class="divide-y divide-indigo-300">
<div class="py-4 px-4 2xl:px-28 lg:items-center flex flex-col lg:grid gap-2 lg:gap-5 grid-cols-12 md:space-x-4">
<div class="col-span-4 flex items-center">
<div class="flex-shrink-0 mr-5">
<div class="w-14 h-14 md:w-20 md:h-20 rounded-full bg-cover bg-center" style="background-image: url('/image/card1.jpg');"></div>
</div>
<div class="flex flex-col">
<p class="truncate text-base lg:text-lg font-semibold text-orange">Сергей Сергеев</p>
<p class="truncate lg:mt-1 text-base text-gray-light">10 сен в 17:20</p>
</div>
</div>
<div class="col-span-6 text-white xl:text-xl">
оценил(а) вашу фотографию
</div>
<div class="col-span-2 flex lg:justify-end">
<img class="object-cover w-20 h-20" src="/image/user_card2.png" alt="">
</div>
</div>
<div class="py-4 px-4 2xl:px-28 lg:items-center flex flex-col lg:grid gap-2 lg:gap-5 grid-cols-12 md:space-x-4">
<div class="col-span-4 flex items-center">
<div class="flex-shrink-0 mr-5">
<div class="w-14 h-14 md:w-20 md:h-20 rounded-full bg-cover bg-center" style="background-image: url('/image/card1.jpg');"></div>
</div>
<div class="flex flex-col">
<p class="truncate text-base lg:text-lg font-semibold text-orange">Сергей Сергеев</p>
<p class="truncate lg:mt-1 text-base text-gray-light">10 сен в 17:20</p>
</div>
</div>
<div class="col-span-6 flex flex-col text-white xl:text-xl">
<span>оставил(а) комментарий:</span>
<span class="truncate text-base text-gray-light">Очень красиво</span>
</div>
<div class="col-span-2 flex lg:justify-end">
<a href="#" class="text-pink text-lg">Перейти</a>
</div>
</div>
<div class="py-4 px-4 2xl:px-28 lg:items-center flex flex-col lg:grid gap-2 lg:gap-5 grid-cols-12 md:space-x-4">
<div class="col-span-4 flex items-center">
<div class="flex-shrink-0 mr-5">
<div class="w-14 h-14 md:w-20 md:h-20 rounded-full bg-cover bg-center" style="background-image: url('/image/card1.jpg');"></div>
</div>
<div class="flex flex-col">
<p class="truncate text-base lg:text-lg font-semibold text-orange">Сергей Сергеев</p>
<p class="truncate lg:mt-1 text-base text-gray-light">10 сен в 17:20</p>
</div>
</div>
<div class="col-span-6 flex flex-col text-white xl:text-xl">
<span>оставил(а) комментарий:</span>
<span class="truncate text-base text-gray-light">Очень красиво</span>
</div>
<div class="col-span-2 flex lg:justify-end">
<a href="#" class="text-pink text-lg">Перейти</a>
</div>
</div>
<div class="py-4 px-4 2xl:px-28 lg:items-center flex flex-col lg:grid gap-2 lg:gap-5 grid-cols-12 md:space-x-4">
<div class="col-span-4 flex items-center">
<div class="flex-shrink-0 mr-5">
<div class="w-14 h-14 md:w-20 md:h-20 rounded-full bg-cover bg-center" style="background-image: url('/image/card1.jpg');"></div>
</div>
<div class="flex flex-col">
<p class="truncate text-base lg:text-lg font-semibold text-orange">Сергей Сергеев</p>
<p class="truncate lg:mt-1 text-base text-gray-light">10 сен в 17:20</p>
</div>
</div>
<div class="col-span-6 flex flex-col text-white xl:text-xl">
<span>оставил(а) комментарий:</span>
<span class="truncate text-base text-gray-light">Очень красиво</span>
</div>
<div class="col-span-2 flex lg:justify-end">
<a href="#" class="text-pink text-lg">Перейти</a>
</div>
</div>
<div class="py-4 px-4 2xl:px-28 lg:items-center flex flex-col lg:grid gap-2 lg:gap-5 grid-cols-12 md:space-x-4">
<div class="col-span-4 flex items-center">
<div class="flex-shrink-0 mr-5">
<div class="w-14 h-14 md:w-20 md:h-20 rounded-full bg-cover bg-center" style="background-image: url('/image/card1.jpg');"></div>
</div>
<div class="flex flex-col">
<p class="truncate text-base lg:text-lg font-semibold text-orange">Сергей Сергеев</p>
<p class="truncate lg:mt-1 text-base text-gray-light">10 сен в 17:20</p>
</div>
</div>
<div class="col-span-6 flex flex-col text-white xl:text-xl">
<span>оставил(а) комментарий:</span>
<span class="truncate text-base text-gray-light">Очень красиво</span>
</div>
<div class="col-span-2 flex lg:justify-end">
<a href="#" class="text-pink text-lg">Перейти</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Layout from '@/Shared/Layout'
import SettingsMenu from '@/Shared/LayoutParts/SettingsMenu'
import MetaHead from '@/Shared/MetaHead'
export default {
layout: Layout,
components: {
MetaHead,
SettingsMenu,
},
methods: {
},
}
</script>

View File

@@ -0,0 +1,195 @@
<template>
<meta-head title="Мои настройки"></meta-head>
<div class="xl:container xl:mx-auto px-2 md:px-3">
<div class="mt-16 shadow-classic rounded-md bg-indigo-200">
<div class="flex flex-col md:grid grid-cols-6 lg:grid-cols-5">
<settings-menu />
<div class="col-span-4">
<div class="m-4 lg:m-8">
<div class="flex flex-col xl:flex-row">
<div class="xl:mr-24">
<div class="flex items-center">
<div class="flex-shrink-0 mr-5">
<user-avatar :user='user' class="w-20 h-20 text-lg" />
</div>
<div class="flex flex-col">
<p class="text-base lg:text-xl font-semibold text-gray">{{user.name}}</p>
<p class="lg:mt-1 text-base text-gray-light">@{{user.username}}</p>
</div>
</div>
<input ref="fileavatar" class="hidden" accept="image/png, image/jpeg, image/jpg" type="file" @change="previewFiles">
<input ref="filebanner" class="hidden" accept="image/png, image/jpeg, image/jpg" type="file" @change="previewFilesBanner">
<div>
<div v-if="$page.props.errors.avatar" class="text-red lg:text-lg">
{{$page.props.errors.avatar}}
</div>
<button v-if="!user.photo_path" @click="changeAvatar" class="hover:underline mt-2 text-left lg:mt-5 default lg:text-lg text-orange">
Изменить фото профиля
</button>
<button v-else @click="removeAvatar" class="hover:underline mt-2 text-left lg:mt-5 default lg:text-lg text-red">
Удалить фото
</button>
</div>
</div>
<div class="mt-5 xl:mt-0">
<div class="flex items-center">
<div class="flex-shrink-0 mr-5">
<user-banner class="w-60 lg:w-96 h-20 rounded-xl bg-indigo-300" :user='user' size='banner' />
</div>
</div>
<div>
<div v-if="$page.props.errors.banner" class="text-red lg:text-lg">
{{$page.props.errors.banner}}
</div>
<button v-if="!user.banner_path" @click="changeBanner" class="hover:underline mt-2 text-left lg:mt-5 default lg:text-lg text-orange">
Изменить баннер профиля
</button>
<button v-else @click="removeBanner" class="hover:underline mt-2 text-left lg:mt-5 default lg:text-lg text-red">
Удалить баннер
</button>
</div>
</div>
</div>
<form @submit.prevent="submit" class="mt-10 grid gap-4 lg:gap-10 grid-cols-1 lg:grid-cols-2">
<div class="flex flex-col">
<text-input v-model="form.first_name" :error="form.errors.first_name" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light" label="Имя" />
</div>
<div class="flex flex-col">
<text-input v-model="form.last_name" :error="form.errors.last_name" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light" label="Фамилия" />
</div>
<div class="flex flex-col">
<text-input v-model="form.username" :error="form.errors.username" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light" label="Тег" />
</div>
<div class="flex flex-col">
<text-input v-model="form.date_of_birth" :error="form.errors.date_of_birth" type="date" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light" label="Дата рождения" />
</div>
<div class="flex flex-col">
<text-input v-model="form.email" :error="form.errors.email" type="email" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light" label="Почта" />
</div>
<div class="flex flex-col">
<text-input v-model="form.phone" :error="form.errors.phone" type="tel" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light" label="Телефон" />
</div>
<div>
<div class="text-gray-light text-lg mb-2">Пол</div>
<div class="flex space-x-6">
<div class="flex items-center">
<input id="user-sex-1" v-model="form.sex" value="1" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="user-sex-1" class="select-none ml-3 text-gray">Женский</label>
</div>
<div class="flex items-center">
<input id="user-sex-2" v-model="form.sex" value="2" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="user-sex-2" class="select-none ml-3 text-gray">Мужской</label>
</div>
</div>
</div>
<div class="lg:col-span-2">
<div class="flex flex-col">
<textarea-input label="О себе" v-model="form.about" :error="form.errors.about" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md" cols="30" rows="2"></textarea-input>
</div>
</div>
<div class="flex flex-wrap -my-1 -mx-3">
<loading-button :loading="form.processing" class="mx-3 my-1 transition shadow-none hover:shadow-classic2 inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-orange focus:outline-none" type="submit">Сохранить</loading-button>
<button type="button"
class="mx-3 my-1 default text-lg text-orange">
Удалить аккаунт
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Layout from '@/Shared/Layout'
import SettingsMenu from '@/Shared/LayoutParts/SettingsMenu'
import LoadingButton from "@/Shared/Form/LoadingButton";
import UserAvatar from '@/Shared/Misc/UserAvatar'
import UserBanner from '@/Shared/Misc/UserBanner'
import MetaHead from '@/Shared/MetaHead'
import TextInput from '@/Shared/Form/TextInput'
import TextareaInput from '@/Shared/Form/TextareaInput'
import { useForm } from "@inertiajs/inertia-vue3";
import { Inertia } from "@inertiajs/inertia";
import { toRefs } from "vue";
export default {
layout: Layout,
components: {
MetaHead,
UserAvatar,
UserBanner,
TextInput,
TextareaInput,
LoadingButton,
SettingsMenu,
},
props: {
user: Object,
},
methods: {
previewFilesBanner(event){
const file = event.target.files[0];
Inertia.post(route("image.banner"), {
_method: 'put',
banner: file,
})
},
previewFiles(event){
const file = event.target.files[0];
Inertia.post(route("image.avatar"), {
_method: 'put',
avatar: file,
})
},
changeBanner(){
this.$refs.filebanner.click();
},
removeBanner(){
Inertia.post(route("image.banner.remove"), {
_method: 'delete',
})
},
changeAvatar(){
this.$refs.fileavatar.click();
},
removeAvatar(){
Inertia.post(route("image.avatar.remove"), {
_method: 'delete',
})
}
},
setup(props) {
const { user } = toRefs(props);
const form = useForm({
first_name: user.value.first_name,
last_name: user.value.last_name,
username: user.value.username,
email: user.value.email,
phone: user.value.phone,
sex: user.value.sex,
date_of_birth: user.value.date_of_birth,
about: user.value.about,
password: null,
});
const submit = () => {
form.put(route("users.update", user.value.id));
};
return { form, submit }
},
}
</script>

View File

@@ -0,0 +1,47 @@
<template>
<meta-head title="Покупки"></meta-head>
<div class="xl:container xl:mx-auto px-2 md:px-3">
<div class="mt-16 shadow-classic rounded-md bg-indigo-200">
<div class="flex flex-col md:grid grid-cols-6 lg:grid-cols-5">
<settings-menu />
<div class="col-span-4">
<div class="m-4 lg:m-8 grid grid-cols-2 sm:grid-cols-3 xl:grid-cols-4 gap-2 lg:gap-4">
<inertia-link :href="route('setting.show.purchases', feed.id)" v-for="feed in feeds" :key="feed.id" class="block contain relative overflow-hidden">
<feed-header-misc :count="1" :type="feed.type" />
<div>
<feed-preview class="w-full h-36 md:h-72 object-cover" :type="feed.type" :source='feed.preview' />
</div>
<p class="mt-2 text-gray-light text-sm">Цена: {{feed.price}}</p>
<p class="mt-2 text-gray-light text-sm">Дата покупки: {{feed.purchase_date}}</p>
</inertia-link>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Layout from "@/Shared/Layout";
import SettingsMenu from "@/Shared/LayoutParts/SettingsMenu";
import MetaHead from "@/Shared/MetaHead";
import Feed from "@/Shared/Feed/Feed";
import FeedHeaderMisc from "@/Shared/Feed/HeaderMisc";
import FeedPreview from "@/Shared/Feed/FeedPreview";
export default {
layout: Layout,
components: {
Feed,
MetaHead,
SettingsMenu,
FeedHeaderMisc,
FeedPreview,
},
props: {
feeds: Array,
},
methods: {},
};
</script>

View File

@@ -0,0 +1,95 @@
<template>
<meta-head title="Скачать медиа контент"></meta-head>
<div class="xl:container xl:mx-auto px-2 md:px-3">
<div class="mt-16 shadow-classic rounded-md bg-indigo-200">
<div class="flex flex-col md:grid grid-cols-6 lg:grid-cols-5">
<settings-menu />
<div class="col-span-4 p-5">
<div class="mb-4 flex items-center text-gray-light text-lg font-medium">
<inertia-link :href="route('setting.purchases')" class="block hover:underline">Вернуться</inertia-link>
<span class="px-3">/</span>
<h1 class="text-gray">Скачать медиа контент</h1>
</div>
<div class="my-8 flex items-center justify-between">
<inertia-link :href="route('profile.user', seller.username)" class="flex items-center">
<div class="flex-shrink-0 block mr-2 md:mr-4">
<user-avatar :user='seller' size='small' class="w-10 h-10 md:w-16 md:h-16 text-lg" />
</div>
<div class="flex flex-col">
<span class="text-sm md:text-base block font-medium text-white">{{ seller.name }}</span>
<span class="text-xs text-gray-light">продавец</span>
</div>
</inertia-link>
<div class="text-right">
<p class="mt-2 text-gray-light text-sm">Цена: {{purchase.price}}</p>
<p class="mt-2 text-gray-light text-sm">Дата покупки: {{purchase.purchase_date}}</p>
</div>
</div>
<div v-if="purchase.title" class="text-lg text-gray font-semibold">
{{purchase.title}}
</div>
<div v-if="purchase.body" class="text-lg mt-4 text-gray-light" v-html="purchase.body"></div>
<div class="mt-4 ">
<component
:is="currentTypeNode"
:purchase="purchase"
></component>
</div>
<div class="mt-12 flex -mx-3 -my-1 flex-wrap">
<a :href="route('download.purchases', purchase.id)" class="mx-3 my-1 transition shadow-none hover:shadow-classic2 inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-orange focus:outline-none">
Скачать архив
</a>
<inertia-link :href="route('setting.purchases')"
class="mx-3 my-1 transition shadow-none hover:shadow-classic inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-indigo-300 focus:outline-none">
Вернуться
</inertia-link>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Layout from "@/Shared/Layout";
import MetaHead from "@/Shared/MetaHead";
import PurchaseImages from "@/Shared/Purchase/PurchaseImages";
import PurchaseMusics from "@/Shared/Purchase/PurchaseMusics";
import SettingsMenu from "@/Shared/LayoutParts/SettingsMenu";
import UserAvatar from '@/Shared/Misc/UserAvatar'
export default {
layout: Layout,
components: {
MetaHead,
PurchaseImages,
PurchaseMusics,
SettingsMenu,
UserAvatar,
},
props: {
purchase: Object,
seller: Object,
},
computed: {
currentTypeNode() {
return "purchase-" + this.purchase.type;
},
},
};
</script>

View File

@@ -0,0 +1,78 @@
<template>
<meta-head title="Тарифы"></meta-head>
<div class="xl:container xl:mx-auto px-2 md:px-3">
<div class="mt-16 shadow-classic rounded-md bg-indigo-200">
<div class="flex flex-col md:grid grid-cols-6 lg:grid-cols-5">
<settings-menu />
<div class="col-span-4">
<div class="mx-4 2xl:mx-28 my-8">
<h2 class="text-xl lg:text-2xl xl:text-4xl text-white font-semibold">
Выберите тариф, который подходит именно вам
</h2>
<p class="mt-4 lg:text-xl xl:text-2xl text-white">
Более 1 млн фотографий, видео и музыки в постоянном доступе для вас!
</p>
<p v-if="lastSubscription" class="mt-4 xl:text-xl text-green">
Дата окончания подписки:
<span class="block md:inline-block">{{ lastSubscription.endDateTime }} ({{ lastSubscription.package.name }})</span>
</p>
<div v-for="plan in plans" :key='plan.id' :class="[lastSubscription?.package.id === plan.id ? 'border-l-4 lg:border-l-8 border-orange' : '' ,'mt-7 p-7 xl:mt-14 xl:p-14 shadow-classic rounded-md bg-indigo-100']">
<div class="flex flex-col lg:grid grid-cols-6 gap-3 items-center">
<div class="col-start-1 col-end-4 flex flex-col items-center lg:items-start text-center lg:text-left">
<span class="text-xl md:text-2xl lg:text-3xl xl:text-4xl text-white font-medium">{{plan.name}}</span>
<span class="mt-4 text-lg xl:text-2xl text-gray-light">For individuals that need advanced recording & editing.</span>
</div>
<div class="col-start-5 col-end-7 flex flex-col items-center">
<span class="text-3xl lg:text-4xl xl:text-6xl text-white font-bold">{{plan.price}}</span>
<button type="button"
@click="subsPlan(plan.id)"
:class="[lastSubscription?.package.id === plan.id ? 'bg-white border border-green text-green' : 'text-white bg-pink hover:shadow-pink' , 'mt-4 my-1 transition shadow-none inline-flex items-center px-8 py-3 justify-center text-base rounded-3xl focus:outline-none']">
<span v-if="lastSubscription?.package.id === plan.id">
активен
</span>
<span v-else>
выбрать тариф
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { Inertia } from "@inertiajs/inertia";
import Layout from '@/Shared/Layout'
import SettingsMenu from '@/Shared/LayoutParts/SettingsMenu'
import MetaHead from '@/Shared/MetaHead'
export default {
layout: Layout,
components: {
MetaHead,
SettingsMenu,
},
props:{
plans: Array,
lastSubscription: Object,
},
methods: {
subsPlan(id) {
Inertia.post(route("users.plan", id), {
preserveScroll: true,
preserveState: true,
});
},
},
}
</script>

View File

@@ -0,0 +1,132 @@
<template>
<meta-head title="Пользователи"></meta-head>
<div class="mt-16 container mx-auto px-2 md:px-6 2xl:px-28 buttons-filter-line">
<div class="md:flex items-center mb-5">
<div class="flex-1 relative mb-5 md:mb-0 md:mr-10">
<div class="absolute inset-y-0 left-3 flex items-center z-[1]">
<svg class="flex-shrink-0 h-5 w-5 text-gray-light" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" fill="currentColor">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M11 4a7 7 0 100 14 7 7 0 000-14zm-9 7a9 9 0 1118 0 9 9 0 01-18 0z" />
<path fill-rule="evenodd" clip-rule="evenodd"
d="M15.943 15.943a1 1 0 011.414 0l4.35 4.35a1 1 0 01-1.414 1.414l-4.35-4.35a1 1 0 010-1.414z" />
</svg>
</div>
<input
v-model="form.search"
class="relative w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light !pl-10 h-14" placeholder="Поиск"
type="search">
</div>
<div>
<div class="flex space-x-6">
<div class="flex items-center">
<input id="user-sex-1" v-model="form.sex" value="1" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="user-sex-1" class="select-none ml-3 text-gray text-xs md:text-base">Женский</label>
</div>
<div class="flex items-center">
<input id="user-sex-2" v-model="form.sex" value="2" type="radio" class="h-5 w-5 text-orange border-gray-light focus:ring-transparent focus:ring-offset-transparent">
<label for="user-sex-2" class="select-none ml-3 text-gray text-xs md:text-base">Мужской</label>
</div>
</div>
</div>
</div>
<div v-show="users.length" class="grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 cards-block rounded-md bg-indigo-200 shadow-classic grid gap-2 lg:gap-4 grid-cards p-2 lg:p-5">
<div v-for="user in users" :key='user.id' class=" user-card relative">
<div class="absolute inset-x-0 top-4 z-10 flex justify-center">
<toggle
@clicked='susbscribe'
:user_id='user.id'
:enabled="user.is_sub"
textin='Подписаться' textout='Отписаться' />
</div>
<div class="absolute inset-x-0 bottom-4 z-10 flex justify-center">
<div class="flex flex-col items-center">
<inertia-link :href="route('profile.user', user.username)" class="block flex-shrink-0">
<user-avatar :user='user' size='small' class="border border-white shadow-classic h-20 w-20 text-lg" />
</inertia-link>
<inertia-link :href="route('profile.user', user.username)" class="mt-2 block text-white text-sm text-center">
<p class="">{{user.name}}</p>
<p class="text-xs">{{user.username}}</p>
</inertia-link>
</div>
</div>
<div class="gradient-profile relative overflow-hidden">
<user-banner class="h-72 bg-indigo-300" :user='user' size='banner' />
</div>
</div>
</div>
<div v-show="users.length == 0">
<p class=" text-center md:text-2xl text-gray-light ">Пользователи не найдены</p>
</div>
</div>
</template>
<script>
import MetaHead from '@/Shared/MetaHead'
import Toggle from '@/Shared/Form/Toggle'
import UserAvatar from '@/Shared/Misc/UserAvatar'
import UserBanner from '@/Shared/Misc/UserBanner'
import Layout from '@/Shared/Layout'
import throttle from 'lodash/throttle'
import pickBy from 'lodash/pickBy'
import { Inertia } from "@inertiajs/inertia";
export default {
components: {
MetaHead,
UserAvatar,
UserBanner,
Toggle,
},
layout: Layout,
props: {
users: Array,
filters: Object,
},
data() {
return {
form: {
search: this.filters.search,
sex: this.filters.sex,
},
}
},
watch: {
form: {
handler: throttle(function() {
let query = pickBy(this.form)
Inertia.get(this.route('users.index', Object.keys(query).length ? query : { remember: 'forget' }),
{},
{
preserveScroll: true,
preserveState: true,
}
)
}, 300),
deep: true,
},
},
methods:{
susbscribe(user_id)
{
Inertia.post(route('users.subs', user_id), {}, { preserveScroll: true, preserveState: true })
}
}
}
</script>

View File

@@ -0,0 +1,101 @@
<template>
<meta-head title="Загрузить видео"></meta-head>
<div class="mt-16 container mx-auto px-2 md:px-6 2xl:px-28 buttons-filter-line">
<form @submit.prevent="submit" class=" bg-indigo-200 shadow-classic rounded-md p-5">
<div class="mb-4 flex items-center text-gray-light text-lg font-medium">
<inertia-link :href="route('profile.user', $page.props.auth.user.username)" class="block hover:underline">
Вернуться
</inertia-link>
<span class="px-3">/</span>
<h1 class="text-gray">Загрузка видео</h1>
</div>
<div class="space-y-5">
<div class="flex flex-col">
<text-input v-model="form.title" :error="form.errors.title" type="text" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light" label="Название" />
</div>
<div class="flex flex-col">
<textarea-input v-model="form.body" :error="form.errors.body" class="focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md" cols="30" rows="4" label="Описание" />
</div>
<div class="flex flex-col">
<file-input-multiple
v-model="form.videos"
accept=".mp4"
:error="form.errors.videos"
label="Выбрать видео"
/>
</div>
<div class="flex flex-col">
<file-input
v-model="form.preview"
accept="image/png, image/jpeg, image/jpg"
:error="form.errors.preview"
label="Загрузить превью"
/>
</div>
<div class="text-gray-light">
<input class="w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md" placeholder="#tags" type="text">
</div>
</div>
<div class="mt-12 flex flex-wrap -my-1 -mx-3">
<progress
class="mx-3 my-1 w-full"
v-if="form.progress"
:value="form.progress.percentage"
max="100"
>
{{ form.progress.percentage }}%
</progress>
<loading-button :loading="form.processing" class="mx-3 my-1 transition shadow-none hover:shadow-classic2 inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-orange focus:outline-none" type="submit">
Создать
</loading-button>
<button type="button"
class="mx-3 my-1 transition shadow-none hover:shadow-classic inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-indigo-300 focus:outline-none">
Отменить
</button>
</div>
</form>
</div>
</template>
<script>
import Layout from '@/Shared/Layout'
import MetaHead from '@/Shared/MetaHead'
import TextInput from '@/Shared/Form/TextInput'
import FileInputMultiple from '@/Shared/Form/FileInputMultiple'
import FileInput from '@/Shared/Form/FileInput'
import TextareaInput from '@/Shared/Form/TextareaInput'
import LoadingButton from "@/Shared/Form/LoadingButton";
import { useForm } from "@inertiajs/inertia-vue3";
export default {
components: {
MetaHead,
TextInput,
FileInput,
FileInputMultiple,
LoadingButton,
TextareaInput,
},
layout: Layout,
setup() {
const form = useForm({
title: null,
body: null,
preview: null,
videos: null,
});
const submit = () => {
form.post(route("video.store"));
};
return { form, submit }
},
}
</script>

View File

@@ -0,0 +1,97 @@
<template>
<meta-head title="Видео"></meta-head>
<div class="mb-6 py-3 banner relative bg-center bg-no-repeat bg-cover"
style="background-image: url('/image/bg-home.jpg');">
<div class="h-52 flex justify-center items-center text-center">
<div class="max-w-4xl text-gray px-3">
<h1
class=" text-xl md:text-2xl lg:text-3xl xl:text-5xl text-white font-semibold xl:leading-relaxed">
Видео</h1>
<inertia-link :href="route('video.create')"
class="mt-8 inline-flex tracking-wide items-center px-8 md:px-12 py-3 border border-white text-sm lg:text-lg text-white rounded-full bg-transparent hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2">
Загрузить
</inertia-link>
</div>
</div>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3 buttons-filter-line">
<div class=" relative mb-5">
<div class="absolute inset-y-0 left-3 flex items-center z-[1]">
<svg class="flex-shrink-0 h-5 w-5 text-gray-light" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" fill="currentColor">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M11 4a7 7 0 100 14 7 7 0 000-14zm-9 7a9 9 0 1118 0 9 9 0 01-18 0z" />
<path fill-rule="evenodd" clip-rule="evenodd"
d="M15.943 15.943a1 1 0 011.414 0l4.35 4.35a1 1 0 01-1.414 1.414l-4.35-4.35a1 1 0 010-1.414z" />
</svg>
</div>
<input
class="relative w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light !pl-10 h-14" placeholder="Поиск"
type="search">
</div>
<div class="grid gap-2 md:gap-5 grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6">
<inertia-link :href="route('list.videos')"
:class="[active_button == 'new' ? 'bg-orange shadow-classic2' : 'shadow-classic bg-indigo-200 hover:bg-orange' , 'transition inline-flex items-center px-3 py-3 lg:px-6 lg:py-6 xl:px-10 text-sm lg:text-lg justify-center rounded-md text-white focus:outline-none']">
Новинки
</inertia-link >
<inertia-link :href="route('list.videos')"
:data="{ filter: 'hot' }"
:class="[active_button == 'hot' ? 'bg-orange shadow-classic2' : 'shadow-classic bg-indigo-200 hover:bg-orange' , 'transition inline-flex items-center px-3 py-3 lg:px-6 lg:py-6 xl:px-10 text-sm lg:text-lg justify-center shadow-classic rounded-md text-white focus:outline-none']">
<svg class="-ml-1 mr-2 h-4 w-4 md:h-5 md:w-5 flex-shrink-0" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
d="M14.422 6.243c-3.57-2.172-1.895-5.238-1.824-5.365A.586.586 0 0012.09 0c-1.837 0-3.276.522-4.276 1.552-1.71 1.76-1.63 4.498-1.597 5.667.004.13.007.242.007.325 0 .868.14 1.67.263 2.377.079.456.147.85.16 1.159.012.331-.048.407-.05.41-.01.01-.081.049-.276.049a.657.657 0 01-.53-.235c-.565-.634-.604-2.365-.496-3.307a.586.586 0 00-.582-.654c-1.521 0-2.658 2.488-2.658 4.712 0 1.046.21 2.07.625 3.045a8.081 8.081 0 001.7 2.527C5.894 19.157 7.89 20 10 20c2.119 0 4.114-.83 5.618-2.34a7.892 7.892 0 002.327-5.605c0-2.692-2.107-4.95-3.523-5.812zM10 18.828c-3.671 0-6.773-3.101-6.773-6.773 0-.893.213-1.83.585-2.571.086-.173.175-.322.263-.447.01.967.163 2.284.841 3.046.366.41.852.627 1.405.627.518 0 .912-.156 1.172-.466.486-.578.337-1.436.148-2.524-.115-.66-.245-1.409-.245-2.176 0-.1-.003-.22-.007-.359-.032-1.107-.099-3.412 1.265-4.817.613-.63 1.467-1.014 2.55-1.145-.123.406-.228.92-.232 1.497-.01 1.27.476 3.085 2.841 4.524 1.145.696 2.96 2.618 2.96 4.811A6.78 6.78 0 0110 18.828z" />
</svg>
Популярные
</inertia-link >
</div>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3 my-6">
<button class="button-default text-gray text-lg">Очистить фильтры</button>
</div>
<div class="xl:container xl:mx-auto px-2 md:px-3">
<div class="grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 cards-block rounded-md bg-indigo-200 shadow-classic grid gap-2 lg:gap-4 grid-cards p-2 lg:p-5">
<feed
:self-feed="false"
:feeds="feeds"
/>
</div>
</div>
</template>
<script>
import Feed from "@/Shared/Feed/Feed";
import Layout from '@/Shared/Layout'
import MetaHead from '@/Shared/MetaHead'
export default {
layout: Layout,
components: {
MetaHead,
Feed
},
props: {
feeds: Array,
active_button: String,
},
methods: {
},
}
</script>

View File

@@ -0,0 +1,306 @@
<template>
<div class="col-span-7 md:col-span-5 lg:col-span-3 player-widget">
<div
@click="openFull"
ref="topbar"
class="
player-line
rounded-md
transition-colors
bg-transparent
hover:bg-orange-min
flex
items-center
space-x-3
p-2
cursor-pointer
"
>
<button @click.stop="skipTrack('prev')" class="focus:outline-none text-gray-600 hover:text-gray-800">
<svg
class="w-4 h-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon points="19 20 9 12 19 4 19 20"></polygon>
<line x1="5" y1="19" x2="5" y2="5"></line>
</svg>
</button>
<button
@click.stop="toggleAudio"
class="
flex
h-8
items-center
justify-center
w-8
transition-colors
text-gray-600
hover:text-gray-800
"
>
<PlayIcon v-show="!playing" class="w-8 h-8" />
<StopIcon v-show="playing" class="w-8 h-8" />
</button>
<button @click.stop="skipTrack('next')" class="focus:outline-none text-gray-600 hover:text-gray-800">
<svg
class="w-4 h-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon points="5 4 15 12 5 20 5 4"></polygon>
<line x1="19" y1="5" x2="19" y2="19"></line>
</svg>
</button>
<div v-show="count_playlist" class="text-base truncate select-none">
{{ currentSong.name }}
</div>
</div>
<teleport to="body">
<div v-if="open_drop">
<div
style="
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
z-index: 9998;
background: black;
opacity: 0.2;
"
@click="open_drop = false"
/>
<div
ref="dropdown"
class="z-[9999] player-widget-list w-full lg:w-[48rem]"
>
<div class="shadow-classic rounded-md bg-indigo-200">
<div
v-show="count_playlist"
@click.prevent="updateSeek"
class="overflow-hidden bg-orange relative h-2 mt-2 mb-2"
>
<div
:style="{ transform: `translate3d(${playerProgress}, 0, 0)` }"
class="will-change-transform absolute transition-transform h-full bg-white flex items-center justify-end w-full"
>
</div>
</div>
<div
class="
p-2
lg:p-4
rounded-md
items-center
grid grid-cols-1
md:grid-cols-10
cursor-pointer
"
>
<div class="col-span-7 flex items-center space-x-3">
<button @click.stop="skipTrack('prev')" class="focus:outline-none text-gray">
<svg
class="w-4 h-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon points="19 20 9 12 19 4 19 20"></polygon>
<line x1="5" y1="19" x2="5" y2="5"></line>
</svg>
</button>
<button
@click.stop="toggleAudio"
class="
flex
h-8
items-center
justify-center
w-8
transition-colors
text-gray
"
>
<PlayIcon v-show="!playing" class="w-8 h-8" />
<StopIcon v-show="playing" class="w-8 h-8" />
</button>
<button @click.stop="skipTrack('next')" class="focus:outline-none text-gray">
<svg
class="w-4 h-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon points="5 4 15 12 5 20 5 4"></polygon>
<line x1="19" y1="5" x2="19" y2="19"></line>
</svg>
</button>
<div class="text-gray-light text-base truncate select-none">
{{ currentSong.name }}
</div>
</div>
<div v-show="count_playlist" class="col-span-1 text-center text-gray-light text-xs select-none">
{{ seek }}
</div>
<div v-show="count_playlist" class="col-span-2 mt-2 md:mt-0 md:ml-auto flex items-center">
<input class="w-full custom-input-range" type="range" v-model="volume" @click.stop="" @input="updateVolume(volume)" max="1" step="0.1" />
<span class="text-gray-light ml-1.5 text-xs">{{ volume * 100 + "%" }}</span>
</div>
</div>
<div class="choices-tabs">
<div class="border-b border-indigo-300">
<nav class="-mb-px flex" aria-label="Tabs">
<a v-for="tab in tabs" :key="tab.key" href="#" @click.prevent="changeTab(tab.key)"
:class="[
current_tab === tab.key ? 'border-orange text-white' : 'border-transparent text-gray-light hover:text-white',
'w-1/2 lg:w-1/4 py-3 lg:py-4 px-1 text-center text-sm border-b-2',
]"
>{{tab.name}}</a>
</nav>
</div>
</div>
<div>
<!-- <audio-tab /> -->
<keep-alive>
<component :is="currentTabComponent"></component>
</keep-alive>
</div>
</div>
</div>
</div>
</teleport>
</div>
</template>
<script>
import Popper from "popper.js";
import { PlayIcon } from "@heroicons/vue/solid";
import { StopIcon } from "@heroicons/vue/solid";
import AudioTabNow from "@/Shared/Tabs/AudioTabNow";
import AudioTabLoaded from "@/Shared/Tabs/AudioTabLoaded";
import { mapActions, mapGetters, mapState } from "vuex";
export default {
name: "Player",
components: {
AudioTabNow,
AudioTabLoaded,
PlayIcon,
StopIcon
},
data() {
return {
tabs: [
{key: 'now', name: 'Текущая'},
{key: 'loaded', name: 'Загруженная'},
{key: 'history', name: 'История'},
],
open_drop: false,
popper: null,
volume: 0.5,
};
},
created() {
this.loadExsitPlaylist();
this.changeVolume(this.volume_step);
this.volume = this.volume_step;
},
computed: {
currentTabComponent() {
return 'audio-tab-' + this.current_tab
},
...mapGetters(["playing", "count_playlist", "volume_step"]),
...mapState({
current_tab: (state) => state.player.tab,
seek: (state) => state.player.seek,
duration: (state) => state.player.duration,
playerProgress: (state) => state.player.playerProgress,
currentSong: (state) => state.player.currentSong,
}),
},
watch: {
open_drop(open_drop) {
if (open_drop) {
this.$nextTick(() => {
if (window.matchMedia("(min-width: 1024px)").matches) {
this.popper = new Popper(this.$refs.topbar, this.$refs.dropdown, {
placement: "bottom-start",
modifiers: {
preventOverflow: { boundariesElement: "scrollParent" },
},
});
}else {
this.popper = new Popper(this.$refs.topbar, this.$refs.dropdown, {
placement: 'bottom-end',
modifiers: {
preventOverflow: {
boundariesElement: 'scrollParent',
padding: 0,
},
offset: {
enabled: true,
offset: '0, 10'
}
},
});
}
});
} else if (this.popper) {
setTimeout(() => this.popper.destroy(), 100);
}
},
},
methods: {
...mapActions([
"toggleAudio",
"updateSeek",
"skipTrack",
"changeVolume",
"tabName",
"loadExsitPlaylist",
]),
openFull() {
this.open_drop = !this.open_drop;
},
updateVolume(volume) {
this.changeVolume(volume);
},
changeTab(name){
this.tabName(name);
},
},
};
</script>

View File

@@ -0,0 +1,62 @@
<template>
<modal-feed
@close-modal="closeModal"
@destroyFeed="destroyFeed"
:modalFeed='modalFeed' :open="show" />
<div v-for="feed in feedLists" :key="feed.id">
<feed-node @open-modal="openModal" :feed="feed" />
</div>
</template>
<script>
import FeedNode from "@/Shared/Feed/FeedNode";
import ModalFeed from "@/Shared/Overlay/ModalFeed";
import { filter } from "lodash";
export default {
components: {
FeedNode,
ModalFeed,
},
props: {
feeds: Array,
selfFeed: Boolean,
selfUser: {
type: Number,
default: 0,
},
},
data() {
return {
showLoadButton: true,
show: false,
entity: {},
feedLists: [],
complaints: [],
modalFeed: {},
};
},
mounted() {
this.feedLists = this.feeds;
},
methods: {
destroyFeed(){
const that = this;
this.feedLists = filter(this.feedLists, function (x) {
return x.id !== that.modalFeed.id;
});
},
openModal(feed) {
this.show = true;
this.modalFeed = feed;
},
closeModal() {
this.show = false;
}
},
};
</script>

View File

@@ -0,0 +1,67 @@
<template>
<component
@click.prevent="openModal(feed)"
@like-feed="likeFeed"
:is="currentTypeNode"
:feed_id="feed.id"
:user="feed.user"
:entity="feed.entity"
></component>
<p class="mt-2 text-gray-light text-sm" v-if="feed.entity.price">Цена: {{feed.entity.price}}</p>
<p class="mt-2 text-gray-light text-sm" v-if="feed.entity.purchase_date">Дата покупки: {{feed.entity.purchase_date}}</p>
</template>
<script>
import { Inertia } from "@inertiajs/inertia";
import FeedImages from "@/Shared/Feed/Images";
import FeedVideos from "@/Shared/Feed/Videos";
import FeedMusics from "@/Shared/Feed/Musics";
import { usePage } from "@inertiajs/inertia-vue3";
export default {
components: {
FeedImages,
FeedVideos,
FeedMusics,
},
props: {
feed: Object,
},
emits: ["openModal"],
computed: {
authUser() {
return usePage().props.value.auth.user;
},
currentTypeNode() {
// if (this.feed.entity.is_paid && this.authUser.id !== this.feed.user.id) {
// return "feed-paids";
// }
return "feed-" + this.feed.type.toLowerCase();
},
},
methods: {
openModal(feed) {
this.$emit("openModal", feed);
},
likeFeed() {
Inertia.post(
route("feed.like", this.feed.id),
{},
{
preserveScroll: true,
preserveState: true,
}
);
if (this.feed.entity.liked) {
this.feed.entity.liked = false;
this.feed.entity.likes--;
} else {
this.feed.entity.liked = true;
this.feed.entity.likes++;
}
},
},
};
</script>

View File

@@ -0,0 +1,24 @@
<template>
<img :src="setImage()" alt="" />
</template>
<script>
export default {
components: { },
props: {
source: String,
type: String,
},
methods: {
setImage() {
if(this.source){
return this.source;
}
if(this.type == 'music'){
return '/image/modalimg1.jpg';
}
return '/image/card4.jpg';
},
},
};
</script>

View File

@@ -0,0 +1,63 @@
<template>
<div
class="
transition-opacity
ease-out
flex
items-center
justify-center
opacity-0
group-hover:opacity-100
bg-indigo-300 bg-opacity-75
z-10
absolute
inset-x-0
bottom-0
p-2
md:p-3
"
>
<div class="misc-info flex space-x-4">
<div :class="[is_like ? 'text-red' : 'text-gray-light', 'flex items-center']">
<button @click.stop="$emit('likeFeed')" class="default">
<svg class="w-5 h-5 flex-shrink-0">
<use xlink:href="#heart"></use>
</svg>
</button>
<span v-show="likes" class="ml-2 text-sm">{{ likes }}</span>
</div>
<div class="flex items-center text-gray-light">
<button class="default">
<svg class="w-5 h-5 flex-shrink-0">
<use xlink:href="#message-circle"></use>
</svg>
</button>
<span v-show="comments" class="ml-2 text-sm">{{
comments
}}</span>
</div>
</div>
<div class="hidden count-views">
<div class="flex items-center text-gray-light">
<span class="mr-2 text-sm">1000</span>
<svg class="w-5 h-5 flex-shrink-0">
<use xlink:href="#eye"></use>
</svg>
</div>
</div>
</div>
</template>
<script>
export default {
components: {},
emits: ["likeFeed"],
props: {
likes: Number,
comments: Number,
is_like: Boolean,
},
};
</script>

View File

@@ -0,0 +1,24 @@
<template>
<div class="absolute z-10 top-3 right-3">
<div class="flex items-center text-white">
<span v-if="count > 1" class="mr-1 text-sm">
{{ count }}
</span>
<svg class="drop-shadow-custom w-5 h-5">
<use v-if="type == 'images'" xlink:href="#imagefeed"></use>
<use v-if="type == 'videos'" xlink:href="#filmmark"></use>
<use v-if="type == 'musics'" xlink:href="#musicmark"></use>
</svg>
</div>
</div>
</template>
<script>
export default {
components: { },
props: {
count: Number,
type: String,
},
};
</script>

View File

@@ -0,0 +1,44 @@
<template>
<div
class="card-block contain group cursor-pointer relative overflow-hidden"
>
<feed-header-misc
:count="entity.collection_medias.length"
type="images"
/>
<feed-footer-misc
:is_like="entity.liked"
:likes="entity.likes"
:comments="entity.comments"
@like-feed="likeFeed"
/>
<div class="relative overflow-hidden">
<img
class="w-full h-36 md:h-72 object-cover"
:src="entity.preview"
alt=""
/>
</div>
</div>
</template>
<script>
import FeedFooterMisc from "@/Shared/Feed/FooterMisc";
import FeedHeaderMisc from "@/Shared/Feed/HeaderMisc";
export default {
components: { FeedFooterMisc, FeedHeaderMisc },
emits: ["likeFeed"],
props: {
entity: Object,
user: Object,
feed_id: Number,
},
methods: {
likeFeed() {
this.$emit("likeFeed");
},
},
};
</script>

View File

@@ -0,0 +1,94 @@
<template>
<div
class="card-block contain group cursor-pointer relative overflow-hidden"
>
<feed-header-misc
:count="entity.collection_medias.length"
type="musics"
/>
<div :class="[playlist_id === feed_id ? '' : 'transition-opacity ease-out opacity-0 group-hover:opacity-100' , ' absolute inset-0 z-10 flex items-center justify-center']">
<div class="w-full grid grid-cols-7 items-center p-1 md:p-3 bg-indigo-300 bg-opacity-75">
<div @click.stop="" class="col-span-1 flex mr-3 text-white">
<div @click.prevent="startPlay(entity.collection_medias[0])" class="inline-block transition-colors hover:text-orange">
<button :class="[ currentSong?.id === entity.collection_medias[0].id ? '' : 'hidden', 'default' ]">
<svg :class="[ playing ? 'hidden' : 'block', 'w-4 h-4 md:w-6 md:h-6' ]">
<use xlink:href="#play"></use>
</svg>
<svg :class="[ playing ? 'block' : 'hidden', 'w-4 h-4 md:w-6 md:h-6' ]">
<use xlink:href="#pause"></use>
</svg>
</button>
<button :class="[ currentSong?.id !== entity.collection_medias[0].id ? '' : 'hidden', 'default' ]">
<svg class="w-4 h-4 md:w-6 md:h-6">
<use xlink:href="#play"></use>
</svg>
</button>
</div>
</div>
<div class="col-span-6 flex flex-col text-white" v-show="playlist_id === feed_id">
<span class="text-xs md:text-base text-gray font-semibold truncate">{{ currentSong.name }}</span>
<span class="text-xs md:text-sm text-gray-light truncate">{{ seek }}</span>
</div>
<div class="col-span-6 flex flex-col text-white" v-show="playlist_id !== feed_id">
<span class="text-xs md:text-base text-gray font-semibold truncate">{{entity.collection_medias[0].name}}</span>
<span class="text-xs md:text-sm text-gray-light truncate">{{entity.collection_medias[0].time}}</span>
</div>
</div>
</div>
<feed-footer-misc
:is_like="entity.liked"
:likes="entity.likes"
:comments="entity.comments"
@like-feed="likeFeed"
/>
<div class="relative overflow-hidden">
<feed-preview class="w-full h-36 md:h-72 object-cover" type="music" :source='entity.preview' />
</div>
</div>
</template>
<script>
import { mapActions, mapState, mapGetters } from "vuex";
import FeedFooterMisc from "@/Shared/Feed/FooterMisc";
import FeedHeaderMisc from "@/Shared/Feed/HeaderMisc";
import FeedPreview from "@/Shared/Feed/FeedPreview";
export default {
components: { FeedFooterMisc, FeedHeaderMisc, FeedPreview },
emits: ["likeFeed"],
props: {
entity: Object,
user: Object,
feed_id: Number,
},
computed: {
...mapGetters(["playing"]),
...mapState({
seek: (state) => state.player.seek,
playlist_id: (state) => state.player.playlist_id,
currentSong: (state) => state.player.currentSong,
}),
},
methods: {
...mapActions(["toggleAudio", "newCurrentPlaylist"]),
startPlay(music) {
if (this.currentSong?.id === music.id) {
this.toggleAudio();
return;
}
this.newCurrentPlaylist([this.entity.collection_medias[0], this.entity.collection_medias, this.feed_id]);
},
likeFeed() {
this.$emit("likeFeed");
},
},
};
</script>

View File

@@ -0,0 +1,41 @@
<template>
<div
class="card-block contain group cursor-pointer relative overflow-hidden"
>
<feed-header-misc
:count="entity.collection_medias.length"
type="videos"
/>
<feed-footer-misc
:is_like="entity.liked"
:likes="entity.likes"
:comments="entity.comments"
@like-feed="likeFeed"
/>
<div class="relative overflow-hidden">
<feed-preview class="w-full h-36 md:h-72 object-cover" :source='entity.preview' />
</div>
</div>
</template>
<script>
import FeedFooterMisc from "@/Shared/Feed/FooterMisc";
import FeedHeaderMisc from "@/Shared/Feed/HeaderMisc";
import FeedPreview from "@/Shared/Feed/FeedPreview";
export default {
components: { FeedFooterMisc, FeedHeaderMisc, FeedPreview },
emits: ["likeFeed"],
props: {
entity: Object,
user: Object,
feed_id: Number,
},
methods: {
likeFeed() {
this.$emit("likeFeed");
},
},
};
</script>

View File

@@ -0,0 +1,41 @@
<template>
<div class="mt-3 md:mt-6 feed-footer">
<div class="flex justify-between">
<div class="misc-info flex space-x-4">
<like-count @likeFeed="likeFeed" :likes="likes" :liked="liked" />
<comment-count :comments="comments" />
<share-count />
</div>
<view-count />
</div>
</div>
</template>
<script>
import LikeCount from "@/Shared/Misc/LikeCount";
import ViewCount from "@/Shared/Misc/ViewCount";
import CommentCount from "@/Shared/Misc/CommentCount";
import ShareCount from "@/Shared/Misc/ShareCount";
export default {
components: {
LikeCount,
CommentCount,
ShareCount,
ViewCount,
},
emits:['likeFeed'],
props: {
comments: Number,
likes: Number,
liked: Boolean,
},
methods:{
likeFeed(){
this.$emit('likeFeed');
},
}
};
</script>

View File

@@ -0,0 +1,62 @@
<template>
<div @click.stop="" class="feed-header flex items-center justify-between">
<div class="flex items-center">
<inertia-link :href="route('profile.user', user.username)" class="flex-shrink-0 block mr-2 md:mr-4">
<user-avatar :user='user' size='small' class="w-10 h-10 md:w-14 md:h-14 text-lg" />
</inertia-link>
<inertia-link :href="route('profile.user', user.username)" class="flex flex-col">
<span class="hover:underline text-sm md:text-base block font-medium text-white">{{ user.name }}</span>
<span class="hover:underline text-xs text-gray-light">{{created_at}}</span>
</inertia-link>
</div>
<div class="flex-shrink-0 text-white">
<dropdown-menu-point>
<MenuItems class="origin-top-right absolute right-0 mt-2 w-64 bg-indigo-300 shadow-lg max-h-60 rounded-md text-base ring-1 ring-indigo-200 overflow-auto focus:outline-none">
<MenuItem v-if="user.id === $page.props.auth.user.id">
<button @click="onRemoveFeed()" class="w-full group flex items-center px-4 py-2 text-base hover:bg-indigo-100 text-gray-light">
<MinusCircleIcon class="mr-3 h-5 w-5 text-gray-400 group-hover:text-orange" aria-hidden="true" />
Удалить
</button>
</MenuItem>
<MenuItem v-if="user.id !== $page.props.auth.user.id">
<inertia-link :href="route('video.create')" class="group flex items-center px-4 py-2 text-base hover:bg-indigo-100 text-gray-light">
<ExclamationIcon class="mr-3 h-5 w-5 text-gray-400 group-hover:text-orange" aria-hidden="true" />
Пожаловаться
</inertia-link>
</MenuItem>
</MenuItems>
</dropdown-menu-point>
</div>
</div>
</template>
<script>
import UserAvatar from '@/Shared/Misc/UserAvatar'
import DropdownMenuPoint from '@/Shared/Form/DropdownMenuPoint'
import { MenuItem, MenuItems } from '@headlessui/vue'
import {
MinusCircleIcon,
ExclamationIcon,
} from '@heroicons/vue/solid'
export default {
components: {
UserAvatar,
DropdownMenuPoint,
MinusCircleIcon,
ExclamationIcon,
MenuItem,
MenuItems,
},
emits: ['onRemoveFeed'],
props: {
user: Object,
created_at: String,
},
methods:{
onRemoveFeed(){
this.$emit('onRemoveFeed');
},
}
};
</script>

View File

@@ -0,0 +1,72 @@
<template>
<modal-feed
@close-modal="closeModal"
:modalFeed='modalFeed'
:open="show"
@destroyFeed="destroyFeed"
/>
<div v-for="feed in feedLists" :key="feed.id">
<feed-list-node @onRemoveFeed="onRemoveFeed" @open-modal="openModal" :feed="feed" />
</div>
</template>
<script>
import FeedListNode from "@/Shared/FeedList/FeedListNode";
import ModalFeed from "@/Shared/Overlay/ModalFeed";
import { Inertia } from "@inertiajs/inertia";
import filter from 'lodash/filter';
export default {
components: {
FeedListNode,
ModalFeed,
},
props: {
feeds: Array,
selfFeed: Boolean,
selfUser: {
type: Number,
default: 0,
},
},
data() {
return {
showLoadButton: true,
show: false,
entity: {},
feedLists: [],
complaints: [],
modalFeed: {},
};
},
mounted() {
this.feedLists = this.feeds;
},
methods: {
onRemoveFeed(id){
Inertia.delete(route('feed.destroy', id), { preserveScroll: true, preserveState: true })
this.destroyFeed(id);
},
destroyFeed(id = null){
const that = this;
this.feedLists = filter(this.feedLists, function (x) {
if(id){
return x.id !== id;
}
return x.id !== that.modalFeed.id;
});
},
openModal(feed) {
this.show = true;
this.modalFeed = feed;
},
closeModal() {
this.show = false;
}
},
};
</script>

View File

@@ -0,0 +1,68 @@
<template>
<component
@click.prevent="openModal(feed)"
@onRemoveFeed='onRemoveFeed'
@like-feed="likeFeed"
:is="currentTypeNode"
:feed_id="feed.id"
:user="feed.user"
:entity="feed.entity"
></component>
</template>
<script>
import { Inertia } from "@inertiajs/inertia";
import FeedImages from "@/Shared/FeedList/Images";
import FeedVideos from "@/Shared/FeedList/Videos";
import FeedMusics from "@/Shared/FeedList/Musics";
import { usePage } from "@inertiajs/inertia-vue3";
export default {
components: {
FeedImages,
FeedVideos,
FeedMusics,
},
props: {
feed: Object,
},
emits: ["openModal", "onRemoveFeed"],
computed: {
authUser() {
return usePage().props.value.auth.user;
},
currentTypeNode() {
if (this.feed.entity.is_paid && this.authUser.id !== this.feed.user.id) {
//return "feed-paid-" + this.feed.type.toLowerCase();
}
return "feed-" + this.feed.type.toLowerCase();
},
},
methods: {
onRemoveFeed(id) {
this.$emit("onRemoveFeed", id);
},
openModal(feed) {
this.$emit("openModal", feed);
},
likeFeed() {
Inertia.post(
route("feed.like", this.feed.id),
{},
{
preserveScroll: true,
preserveState: true,
}
);
if (this.feed.entity.liked) {
this.feed.entity.liked = false;
this.feed.entity.likes--;
} else {
this.feed.entity.liked = true;
this.feed.entity.likes++;
}
},
},
};
</script>

View File

@@ -0,0 +1,75 @@
<template>
<div class="">
<div class="flex items-center border-b border-indigo-100">
<div class="flex-shrink-0 mr-5 w-28 md:w-56">
<feed-preview class="h-28 w-28 md:w-56 md:h-56 object-cover" type="music" :source='preview' />
</div>
<div class="flex flex-col">
<span class="text-base md:text-xl font-semibold text-gray">{{title}}</span>
</div>
</div>
<div data-simplebar class="max-h-72 overflow-auto">
<div class="divide-y divide-indigo-100">
<div
@click.prevent="startPlay(media)"
v-for="media in medias" :key="media.id"
:class="[currentSong?.id === media.id ? 'bg-indigo-300 bg-opacity-25' : 'hover:bg-indigo-300 hover:bg-opacity-25', 'p-4 flex items-center space-x-4']">
<div class="flex">
<toggle-play-button :media_id="media.id" />
</div>
<div class="flex-1 text-sm text-gray-light">
{{media.name}}
</div>
<div class="text-sm text-gray-light">
<div v-if="currentSong?.id === media.id">{{seek}}</div>
<span v-else>{{media.time}}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions, mapState, mapGetters } from "vuex";
import FeedPreview from "@/Shared/Feed/FeedPreview";
import TogglePlayButton from "@/Shared/Misc/TogglePlayButton";
export default {
components: {
FeedPreview,
TogglePlayButton,
},
props: {
medias: Array,
feed_id: Number,
title: String,
preview: String,
},
methods: {
...mapActions(["toggleAudio", "newCurrentPlaylist", "skipToIndexByMusic"]),
startPlay(music) {
if (this.currentSong?.id === music.id) {
this.toggleAudio();
return;
}
// if (this.playlist_id === this.feed_id) {
// this.skipToIndexByMusic(music);
// return;
// }
this.newCurrentPlaylist([music, this.medias, this.feed_id]);
},
},
computed: {
...mapGetters(["playing"]),
...mapState({
playlist_id: (state) => state.player.playlist_id,
seek: (state) => state.player.seek,
currentSong: (state) => state.player.currentSong,
}),
},
};
</script>

View File

@@ -0,0 +1,95 @@
<template>
<div @click.stop="" class="mt-3 rounded-md bg-indigo-300 p-4"
v-if="disabled === 0 && is_paid && $page.props.auth.user.id !== user_id">
<div v-if="bought == 0" class="flex items-center justify-center">
<div class="mr-5 mb-2 md:mb-0 font-bold text-center md:text-left w-full md:w-auto">
Цена: {{price}}
</div>
<div>
<button @click="purchaseFeed" type="button" class="my-1 transition shadow-none hover:shadow-classic2 inline-flex items-center px-8 py-1 md:py-3 justify-center text-sm md:text-base rounded-md text-white bg-pink focus:outline-none">
Купить
</button>
</div>
</div>
<div v-else class="flex flex-wrap items-center justify-center">
<div class="mr-5 mb-2 md:mb-0 font-bold text-center md:text-left w-full md:w-auto">
Данный товар вами куплен
</div>
<button v-if="disable_btn == 0 && paid_open == 0" @click="replaceFeed" type="button" class="my-1 mx-1 transition shadow-none hover:shadow-classic2 inline-flex items-center px-8 py-1 md:py-3 justify-center text-sm md:text-base rounded-md text-white bg-orange focus:outline-none">
Показать
</button>
<inertia-link :href="route('setting.show.purchases', feed_id)" class="my-1 mx-1 transition shadow-none hover:shadow-classic2 inline-flex items-center px-8 py-1 md:py-3 justify-center text-sm md:text-base rounded-md text-white bg-pink focus:outline-none">
Скачать
</inertia-link>
</div>
</div>
<div @click.stop="" v-else-if="is_paid && $page.props.auth.user.id === user_id" class="p-4 text-center">
<button v-if="paid_open === 0" @click="replaceFeed" type="button" class="my-1 mx-1 transition shadow-none hover:shadow-classic2 inline-flex items-center px-8 py-1 md:py-2 justify-center text-sm rounded-md text-white bg-orange focus:outline-none">
Показать платный контент
</button>
</div>
</template>
<script>
import axios from "axios";
export default {
components: {},
emits: ["onReplaceFeed"],
props: {
user_id: Number,
is_paid: Boolean,
feed_id: Number,
price: String,
paid_open: {
type: Number,
default: 0,
},
},
data() {
return {
bought: 0,
disable_btn: 0,
disabled: 1,
};
},
mounted() {
if (this.is_paid) {
axios
.post(route("feeds.purchase_check", this.feed_id))
.then(({ data }) => {
if (data === 1) {
this.bought = 1;
}
this.disabled = 0;
});
}
},
methods: {
purchaseFeed() {
axios.post(route("feed.purchase", this.feed_id)).then(({ data }) => {
if (data.error == 1) {
alert(data.msg);
} else {
this.$emit("onReplaceFeed", data);
this.disable_btn = 1;
this.bought = 1;
}
});
},
replaceFeed() {
axios.post(route("feeds.replace", this.feed_id)).then(({ data }) => {
if (data.collection) {
this.$emit("onReplaceFeed", data);
this.disable_btn = 1;
}
});
},
},
};
</script>

View File

@@ -0,0 +1,68 @@
<template>
<div class="shadow-classic rounded-md bg-indigo-200 p-3 md:px-5 md:py-7">
<feed-header @onRemoveFeed='onRemoveFeed' :created_at='entity.created_at_humans' :user='user' />
<div class="mt-3 md:mt-6 feed-body">
<div class="mb-3 md:mb-6 text-gray text-sm md:text-base">
<div @click.stop="">
{{entity.body}}
</div>
<feed-paid-block
@onReplaceFeed='onReplaceFeed'
:is_paid='entity.is_paid'
:user_id='user.id'
:price='entity.price'
:feed_id='feed_id'
:paid_open='entity.paid_open'
/>
</div>
<div class="grid gap-1 md:gap-3 grid-cols-2 md:grid-cols-[repeat(auto-fit,minmax(280px,1fr))]">
<div v-for="media in entity.collection_medias" :key="media.id">
<img class="w-full h-full object-cover" :src="media.url" alt="">
</div>
</div>
</div>
<feed-footer
@likeFeed='likeFeed'
:likes='entity.likes'
:liked='entity.liked'
:comments='entity.comments'
/>
</div>
</template>
<script>
import FeedHeader from "@/Shared/FeedList/FeedHeader";
import FeedFooter from "@/Shared/FeedList/FeedFooter";
import FeedPaidBlock from "@/Shared/FeedList/FeedPaidBlock";
export default {
components: {
FeedHeader,
FeedFooter,
FeedPaidBlock,
},
emits: ["likeFeed", "onRemoveFeed"],
props: {
entity: Object,
user: Object,
feed_id: Number,
},
methods: {
onReplaceFeed(data) {
this.entity.collection_medias = data.collection;
this.entity.preview = data.preview;
this.entity.paid_open = 1;
},
onRemoveFeed() {
this.$emit("onRemoveFeed", this.feed_id);
},
likeFeed() {
this.$emit("likeFeed");
},
},
};
</script>

View File

@@ -0,0 +1,66 @@
<template>
<div class="shadow-classic rounded-md bg-indigo-200 p-3 md:px-5 md:py-7">
<feed-header :created_at='entity.created_at_humans' :user='user' />
<div @click.stop="" class="mt-3 md:mt-6 feed-body">
<div class="mb-3 md:mb-6 text-gray text-sm md:text-base">
<div @click.stop="">
{{entity.body}}
</div>
<feed-paid-block
@onReplaceFeed='onReplaceFeed'
:is_paid='entity.is_paid'
:user_id='user.id'
:price='entity.price'
:feed_id='feed_id'
:paid_open='entity.paid_open'
/>
</div>
<feed-music-body
:feed_id='feed_id'
:title='entity.title'
:preview='entity.preview'
:medias='entity.collection_medias'
/>
</div>
<feed-footer
@likeFeed='likeFeed'
:likes='entity.likes'
:liked='entity.liked'
:comments='entity.comments'
/>
</div>
</template>
<script>
import FeedHeader from "@/Shared/FeedList/FeedHeader";
import FeedFooter from "@/Shared/FeedList/FeedFooter";
import FeedMusicBody from "@/Shared/FeedList/FeedMusicBody";
import FeedPaidBlock from "@/Shared/FeedList/FeedPaidBlock";
export default {
components: {
FeedHeader,
FeedFooter,
FeedMusicBody,
FeedPaidBlock,
},
emits: ["likeFeed"],
props: {
entity: Object,
user: Object,
feed_id: Number,
},
methods: {
onReplaceFeed(data) {
this.entity.collection_medias = data.collection;
this.entity.preview = data.preview;
this.entity.paid_open = 1;
},
likeFeed() {
this.$emit("likeFeed");
},
},
};
</script>

View File

@@ -0,0 +1,48 @@
<template>
<div class="shadow-classic rounded-md bg-indigo-200 p-3 md:px-5 md:py-7">
<feed-header :created_at='entity.created_at_humans' :user='user' />
<div @click.stop="" class="mt-3 md:mt-6 feed-body">
<div class="mb-3 md:mb-6 text-gray text-sm md:text-base">
{{entity.body}}
</div>
<div class="grid gap-1 md:gap-3 grid-cols-2 md:grid-cols-[repeat(auto-fit,minmax(280px,1fr))]">
<div v-for="media in entity.collection_medias" :key="media.id">
<video :src="media.url" controls></video>
</div>
</div>
</div>
<feed-footer
@likeFeed='likeFeed'
:likes='entity.likes'
:liked='entity.liked'
:comments='entity.comments'
/>
</div>
</template>
<script>
import FeedHeader from '@/Shared/FeedList/FeedHeader'
import FeedFooter from '@/Shared/FeedList/FeedFooter'
export default {
components: {
FeedHeader,
FeedFooter,
},
emits: ["likeFeed"],
props: {
entity: Object,
user: Object,
feed_id: Number,
},
methods: {
likeFeed() {
this.$emit("likeFeed");
},
},
};
</script>

View File

@@ -0,0 +1,71 @@
<template>
<button type="button" @click="show = true">
<slot />
<teleport to="body">
<div v-if="show">
<div style="position: fixed; top: 0; right: 0; left: 0; bottom: 0; z-index: 99998;" @click="show = false" />
<div ref="dropdown" style="position: absolute; z-index: 99999;" @click.stop="show = autoClose ? false : true">
<slot name="dropdown" />
</div>
</div>
</teleport>
</button>
</template>
<script>
import Popper from 'popper.js'
export default {
props: {
placement: {
type: String,
default: 'bottom-end',
},
offset: {
type: String,
default: '0, 10',
},
boundary: {
type: String,
default: 'scrollParent',
},
autoClose: {
type: Boolean,
default: true,
},
},
data() {
return {
show: false,
}
},
watch: {
show(show) {
if (show) {
this.$nextTick(() => {
this.popper = new Popper(this.$el, this.$refs.dropdown, {
placement: this.placement,
modifiers: {
preventOverflow: { boundariesElement: this.boundary, padding: 0},
offset: {
enabled: true,
offset: this.offset
}
},
})
})
} else if (this.popper) {
setTimeout(() => this.popper.destroy(), 100)
}
},
},
mounted() {
document.addEventListener('keydown', (e) => {
if (e.keyCode === 27) {
this.show = false
}
})
},
}
</script>

View File

@@ -0,0 +1,27 @@
<!-- This example requires Tailwind CSS v2.0+ -->
<template>
<Menu as="div" class="relative inline-block text-left z-50">
<div>
<MenuButton class="transition inline-flex items-center justify-center shadow-classic2 rounded-full bg-orange text-white focus:outline-none w-12 h-12">
<svg class="h-4 w-4 md:h-5 md:w-5 flex-shrink-0" 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" ><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
</MenuButton>
</div>
<transition enter-active-class="transition ease-out duration-100" enter-from-class="transform opacity-0 scale-95" enter-to-class="transform opacity-100 scale-100" leave-active-class="transition ease-in duration-75" leave-from-class="transform opacity-100 scale-100" leave-to-class="transform opacity-0 scale-95">
<slot />
</transition>
</Menu>
</template>
<script>
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue'
export default {
components: {
Menu,
MenuButton,
MenuItem,
MenuItems,
},
}
</script>

View File

@@ -0,0 +1,27 @@
<!-- This example requires Tailwind CSS v2.0+ -->
<template>
<Menu as="div" v-slot="{ open }" class="relative inline-block text-left z-50">
<div>
<MenuButton class="transition inline-flex items-center justify-center focus:outline-none ">
<svg :class="[open ? 'rotate-90' : 'rotate-180' ,'transform-gpu transition-transform transform w-6 h-6']">
<use xlink:href="#more-vertical"></use>
</svg>
</MenuButton>
</div>
<transition enter-active-class="transition ease-out duration-100" enter-from-class="transform opacity-0 scale-95" enter-to-class="transform opacity-100 scale-100" leave-active-class="transition ease-in duration-75" leave-from-class="transform opacity-100 scale-100" leave-to-class="transform opacity-0 scale-95">
<slot />
</transition>
</Menu>
</template>
<script>
import { Menu, MenuButton } from '@headlessui/vue'
export default {
components: {
Menu,
MenuButton,
},
}
</script>

View File

@@ -0,0 +1,53 @@
<template>
<div>
<label v-if="label" class="text-gray-light text-lg mb-2">{{ label }}:</label>
<div :class="{ error: error }">
<input ref="file" type="file" :accept="accept" class="hidden" @change="change">
<div v-if="!modelValue" class="py-2">
<button type="button" class="px-6 py-2 bg-indigo-300 focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:outline-none focus:border-transparent rounded-sm text-sm text-white" @click="browse">
Выбрать файл
</button>
</div>
<div v-else class="flex justify-center items-start max-w-lg mt-3 p-2 border rounded-md">
<div class="flex-1 pr-1 text-gray">{{ modelValue.name }} <span class="text-xs text-gray-light">({{ filesize(modelValue.size) }})</span></div>
<button type="button" class="px-4 py-1 bg-indigo-300 hover:bg-indigo-100 rounded-sm text-xs font-medium text-white" @click="remove">
Удалить
</button>
</div>
</div>
<div v-if="error" class="text-red text-sm">{{ error }}</div>
</div>
</template>
<script>
export default {
props: {
modelValue: File,
label: String,
accept: String,
error: String,
},
watch: {
modelValue(value) {
if (!value) {
this.$refs.file.value = ''
}
},
},
methods: {
filesize(size) {
var i = Math.floor(Math.log(size) / Math.log(1024))
return (size / Math.pow(1024, i) ).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i]
},
browse() {
this.$refs.file.click()
},
change(e) {
this.$emit('update:modelValue', e.target.files[0])
},
remove() {
this.$emit('update:modelValue', null)
},
},
}
</script>

View File

@@ -0,0 +1,111 @@
<template>
<div>
<label v-if="label" class="text-gray-light text-lg mb-2">{{ label }}:</label>
<div :class="{ error: error }">
<input
ref="file"
type="file"
:accept="accept"
multiple
class="hidden"
@change="change"
/>
<div v-if="!modelValue" class="py-2">
<button
type="button"
class="px-6 py-2 bg-indigo-300 focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:outline-none focus:border-transparent rounded-sm text-sm text-white"
@click="browse"
>
Выбрать файлы
</button>
</div>
<div v-else class="flex flex-col justify-center max-w-lg mt-3 p-2 border rounded-md">
<div
v-for="(file, index) in modelValue"
:key="index"
class="flex items-center justify-between p-1"
>
<div class="flex-1 pr-1 text-gray">
{{ file.name }}
<span class="text-xs text-gray-light"
>({{ filesize(file.size) }})</span
>
</div>
<button
type="button"
class="px-4 py-1 bg-indigo-300 hover:bg-indigo-100 rounded-sm text-xs font-medium text-white"
@click="remove(index)"
>
Удалить
</button>
</div>
</div>
</div>
<div v-if="error" class="text-red text-sm">{{ error }}</div>
</div>
</template>
<script>
import helper from "@/includes/helper";
export default {
props: {
modelValue: FileList,
label: String,
accept: String,
error: String,
},
emits:['fileTime', 'update:modelValue'],
methods: {
filesize(size) {
var i = Math.floor(Math.log(size) / Math.log(1024));
return (
(size / Math.pow(1024, i)).toFixed(2) * 1 +
" " +
["B", "kB", "MB", "GB", "TB"][i]
);
},
browse() {
this.$refs.file.click();
},
change(e) {
const files = Array.from(e.target.files);
const that = this;
files.map(function (file) {
if(file.type === "audio/mpeg"){
var audioCtx = new (AudioContext || webkitAudioContext)();
var readerAudio = new FileReader();
readerAudio.readAsArrayBuffer(file);
readerAudio.onload = function(ev) {
audioCtx.decodeAudioData(ev.target.result).then(function(buffer) {
that.$emit("fileTime", file.name + ',' + that.formatTimeSong(buffer.duration));
});
};
}
});
this.$emit("update:modelValue", e.target.files);
},
formatTimeSong(value) {
return helper.formatTime(value);
},
remove(file_index) {
const dt = new DataTransfer();
let files = Array.from(this.$refs.file.files);
files.map(function (file, index) {
if (index !== file_index) {
dt.items.add(file);
}
});
if (dt.files.length) {
this.$refs.file.files = dt.files;
this.$emit("update:modelValue", dt.files);
} else {
this.$refs.file.files = null;
this.$emit("update:modelValue", null);
}
},
},
};
</script>

View File

@@ -0,0 +1,14 @@
<template>
<button :disabled="loading">
<div v-if="loading" class="btn-spinner mr-2" />
<slot />
</button>
</template>
<script>
export default {
props: {
loading: Boolean,
},
}
</script>

View File

@@ -0,0 +1,37 @@
<template>
<label class="text-gray-light text-lg mb-2" v-if="label" :for="id">{{ label }}:</label>
<input :id="id" ref="input" v-bind="$attrs" :class="{ error: error }" :type="type" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
<div v-if="error">{{ error }}</div>
</template>
<script>
export default {
props: {
id: {
type: String,
default() {
return `select-input-${Math.random() * 1000}`;
},
},
type: {
type: String,
default: 'text',
},
modelValue: String,
label: String,
error: String,
},
emits: ['update:modelValue'],
methods: {
focus() {
this.$refs.input.focus()
},
select() {
this.$refs.input.select()
},
setSelectionRange(start, end) {
this.$refs.input.setSelectionRange(start, end)
},
},
}
</script>

View File

@@ -0,0 +1,30 @@
<template>
<label class="text-gray-light text-lg mb-2" v-if="label" :for="id">{{ label }}:</label>
<textarea :id="id" ref="input" v-bind="$attrs" :class="{ error: error }" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
<div v-if="error" class="text-red text-sm">{{ error }}</div>
</template>
<script>
export default {
inheritAttrs: false,
props: {
id: {
type: String,
default() {
return `select-input-${Math.random() * 1000}`;
},
},
modelValue: String,
label: String,
error: String,
},
methods: {
focus() {
this.$refs.input.focus()
},
select() {
this.$refs.input.select()
},
},
}
</script>

View File

@@ -0,0 +1,40 @@
<template>
<SwitchGroup @click="clicked" as="div" class="flex items-center">
<Switch v-model="enabled" :class="[enabled ? 'bg-orange' : 'bg-indigo-200', 'relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500']">
<!-- <span class="sr-only">Use setting</span> -->
<span aria-hidden="true" :class="[enabled ? 'translate-x-5' : 'translate-x-0', 'pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200']" />
</Switch>
<SwitchLabel as="span" class="ml-3">
<span v-show="!enabled" class="text-sm text-white">{{textin}}</span>
<span v-show="enabled" class="text-sm text-white">{{textout}}</span>
</SwitchLabel>
</SwitchGroup>
</template>
<script>
import { Switch, SwitchGroup, SwitchLabel } from '@headlessui/vue'
export default {
components: {
Switch,
SwitchGroup,
SwitchLabel,
},
emits: ['clicked'],
props: {
textin: String,
textout: String,
user_id: Number,
enabled: {
type: Boolean,
default: false
},
},
methods: {
clicked(){
this.$emit('clicked', this.user_id);
}
}
}
</script>

View File

@@ -0,0 +1,35 @@
<template>
<header-bar />
<div class="min-h-screen flex overflow-hidden">
<sidebar />
<div class="flex-1 flex flex-col overflow-hidden">
<div class="bg-indigo-300 flex-1 flex items-stretch overflow-hidden">
<main class="flex-1 overflow-y-auto pb-10">
<section class="min-w-0 flex-1 h-full flex flex-col overflow-hidden lg:order-last">
<flash-messages />
<slot />
</section>
</main>
<sidebar-secondary v-if="$page.props.sidebar_layout" />
</div>
</div>
</div>
</template>
<script>
import FlashMessages from '@/Shared/Misc/FlashMessages'
import HeaderBar from '@/Shared/LayoutParts/HeaderBar'
import Sidebar from '@/Shared/LayoutParts/Sidebar'
import SidebarSecondary from '@/Shared/LayoutParts/SidebarSecondary'
export default {
components: {
FlashMessages,
HeaderBar,
Sidebar,
SidebarSecondary,
}
}
</script>

View File

@@ -0,0 +1,35 @@
<template>
<header-bar />
<div class="min-h-screen flex overflow-hidden">
<sidebar />
<div class="flex-1 flex flex-col overflow-hidden">
<div class="bg-indigo-300 flex-1 flex items-stretch overflow-hidden">
<main class="flex-1 overflow-y-auto pb-10">
<section class="min-w-0 flex-1 h-full flex flex-col overflow-hidden lg:order-last">
<flash-messages />
<slot />
</section>
</main>
<sidebar-secondary />
</div>
</div>
</div>
</template>
<script>
import FlashMessages from '@/Shared/Misc/FlashMessages'
import HeaderBar from '@/Shared/LayoutParts/HeaderBar'
import Sidebar from '@/Shared/LayoutParts/Sidebar'
import SidebarSecondary from '@/Shared/LayoutParts/SidebarSecondary'
export default {
components: {
FlashMessages,
HeaderBar,
Sidebar,
SidebarSecondary,
},
}
</script>

View File

@@ -0,0 +1,384 @@
<template>
<header class="w-full sticky top-0 z-[100]">
<div class="relative z-10 bg-orange shadow-xl">
<div
class="
grid grid-cols-12
items-center
pt-2.5
pb-2.5
px-4
sm:px-6
md:space-x-5
lg:space-x-10
"
>
<inertia-link :href="route('dashboard')" class="col-span-1 block flex-shrink-0">
<div class="block md:hidden font-bold text-indigo-300 text-2xl">
T
</div>
<img class="hidden md:block" src="/image/logotype.svg" alt="" />
</inertia-link >
<audio-player />
<div class="col-span-4 h-12 hidden md:flex">
<form class="main-search w-full flex md:ml-0" action="#" method="GET">
<label for="search_field" class="sr-only">Поиск контента</label>
<div
class="relative w-full text-gray-400 focus-within:text-gray-600"
>
<input
name="search_field"
id="search_field"
class="
h-full
w-full
rounded-md
border-transparent
py-2
pr-11
pl-4
text-base
bg-orange-dark
text-white
placeholder-gray
focus:border-transparent
focus:outline-none
focus:ring-2 focus:ring-orange-dark
"
placeholder="Глобальный поиск..."
type="search"
/>
<div
class="
pointer-events-none
absolute
inset-y-0
right-4
flex
items-center
text-gray
"
>
<svg
class="flex-shrink-0 h-6 w-6"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M11 4a7 7 0 100 14 7 7 0 000-14zm-9 7a9 9 0 1118 0 9 9 0 01-18 0z"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M15.943 15.943a1 1 0 011.414 0l4.35 4.35a1 1 0 01-1.414 1.414l-4.35-4.35a1 1 0 010-1.414z"
/>
</svg>
</div>
</div>
</form>
</div>
<div
class="
col-span-4
md:col-span-2
lg:col-span-4
flex
items-center
justify-end
space-x-2
sm:ml-6
sm:space-x-6
"
>
<inertia-link :href="route('setting.money')" class="hidden lg:block default text-sm text-white">
Баланс: {{$page.props.balance}}
</inertia-link>
<button
type="button"
class="
flex
md:hidden
p-1
rounded-full
items-center
justify-center
text-white
focus:outline-none
"
>
<svg
class="w-5 h-5 md:h-6 md:w-6"
xmlns="http://www.w3.org/2000/svg"
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"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
</button>
<div class="relative">
<div
class="
absolute
top-0
right-1
w-2
h-2
md:w-3
md:h-3
bg-pink
rounded-full
"
></div>
<inertia-link
:href="route('setting.notify')"
class="
flex
p-1
rounded-full
items-center
justify-center
text-white
focus:outline-none
"
>
<svg
class="w-5 h-5 md:h-6 md:w-6"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
<path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
</svg>
</inertia-link>
</div>
<dropdown class="flex md:hidden user-menu h-12 w-12 rounded-full items-center justify-center focus:outline-none" placement="bottom-start">
<svg class="h-6 w-6 text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <line x1="3" y1="12" x2="21" y2="12"></line> <line x1="3" y1="6" x2="21" y2="6"></line> <line x1="3" y1="18" x2="21" y2="18"></line> </svg>
<template v-slot:dropdown>
<div class="mobile-user-menu z-50 bg-orange-dark rounded-b-lg">
<div
class="absolute z-50 right-0 top-[-16px] mr-[20px] sm:mr-[20px]"
>
</div>
<ul class="p-6 text-white space-y-6">
<li>
<inertia-link :href="route('setting.money')">Баланс: {{$page.props.balance}}</inertia-link>
</li>
<li>
<inertia-link :href="route('profile.user', $page.props.auth.user.username)">Профиль</inertia-link>
</li>
<li>
<inertia-link :href="route('feeds.layoutsidebar')">Новости</inertia-link>
</li>
<li>
<a href="#"><span class="text-xs rounded-full mr-1">(5)</span> Сообщения</a>
</li>
<li>
<inertia-link :href="route('list.images')">Изображения</inertia-link>
</li>
<li>
<inertia-link :href="route('list.videos')">Видео</inertia-link>
</li>
<li>
<inertia-link :href="route('list.musics')">Музыка</inertia-link>
</li>
<li>
<inertia-link :href="route('users.index')">Пользователи</inertia-link>
</li>
<li>
<inertia-link :href="route('setting.index')">Настройки</inertia-link>
</li>
<li>
<inertia-link as="button" :href="route('logout')" method="delete">Выйти</inertia-link>
</li>
</ul>
</div>
</template>
</dropdown>
<div class="hidden md:block relative flex-shrink-0">
<inertia-link
:href="route('profile.user', $page.props.auth.user.username)"
class="
bg-white
rounded-full
flex
text-sm
focus:outline-none
focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500
"
>
<user-avatar :user='$page.props.auth.user' size='small' class="w-9 h-9 md:h-12 md:w-12 text-lg" />
</inertia-link>
</div>
</div>
</div>
</div>
</header>
<div class=" hidden w-[48rem] z-50 main-search-list shadow-classic rounded-md bg-indigo-200 overflow-hidden " >
<div class="">
<div data-simplebar class="overflow-auto max-h-72">
<div class="text-gray-light divide-y divide-indigo-300">
<!-- s -->
<div class="flex cursor-pointer items-center p-3 hover:bg-indigo-300">
<div class="flex-shrink-0 mr-5">
<img
class="object-cover w-10 h-10"
src="/image/user_card2.png"
alt=""
/>
</div>
<div class="flex-1">
Lorem, ipsum dolor sit amet consectetur
<mark class="text-orange bg-transparent">consectetur</mark> asdasd
....
</div>
<div class="ml-5 flex-shrink-0">
<svg class="drop-shadow-custom w-5 h-5">
<use xlink:href="#musicmark"></use>
</svg>
</div>
</div>
<!-- e -->
<!-- s -->
<div class="flex cursor-pointer items-center p-3 hover:bg-indigo-300">
<div class="flex-shrink-0 mr-5">
<img
class="object-cover w-10 h-10"
src="/image/user_card2.png"
alt=""
/>
</div>
<div class="flex-1">
<mark class="text-orange bg-transparent">consectetur</mark> Lorem,
ipsum dolor sit amet consectetur asdasd ....
</div>
<div class="ml-5 flex-shrink-0">
<svg class="drop-shadow-custom w-5 h-5">
<use xlink:href="#filmmark"></use>
</svg>
</div>
</div>
<!-- e -->
<!-- s -->
<div class="flex cursor-pointer items-center p-3 hover:bg-indigo-300">
<div class="flex-shrink-0 mr-5">
<img
class="object-cover w-10 h-10"
src="/image/user_card2.png"
alt=""
/>
</div>
<div class="flex-1">
<mark class="text-orange bg-transparent">consectetur</mark> Lorem,
ipsum dolor sit amet consectetur asdasd ....
</div>
<div class="ml-5 flex-shrink-0">
<svg class="drop-shadow-custom w-5 h-5">
<use xlink:href="#filmmark"></use>
</svg>
</div>
</div>
<!-- e -->
<!-- s -->
<div class="flex cursor-pointer items-center p-3 hover:bg-indigo-300">
<div class="flex-shrink-0 mr-5">
<img
class="object-cover w-10 h-10"
src="/image/user_card2.png"
alt=""
/>
</div>
<div class="flex-1">
<mark class="text-orange bg-transparent">consectetur</mark> Lorem,
ipsum dolor sit amet consectetur asdasd ....
</div>
<div class="ml-5 flex-shrink-0">
<svg class="drop-shadow-custom w-5 h-5">
<use xlink:href="#filmmark"></use>
</svg>
</div>
</div>
<!-- e -->
<!-- s -->
<div class="flex cursor-pointer items-center p-3 hover:bg-indigo-300">
<div class="flex-shrink-0 mr-5">
<img
class="object-cover w-10 h-10"
src="/image/user_card2.png"
alt=""
/>
</div>
<div class="flex-1">
<mark class="text-orange bg-transparent">consectetur</mark> Lorem,
ipsum dolor sit amet consectetur asdasd ....
</div>
<div class="ml-5 flex-shrink-0">
<svg class="drop-shadow-custom w-5 h-5">
<use xlink:href="#filmmark"></use>
</svg>
</div>
</div>
<!-- e -->
<!-- s -->
<div class="flex cursor-pointer items-center p-3 hover:bg-indigo-300">
<div class="flex-shrink-0 mr-5">
<img
class="object-cover w-10 h-10"
src="/image/user_card2.png"
alt=""
/>
</div>
<div class="flex-1">
<mark class="text-orange bg-transparent">consectetur</mark> Lorem,
ipsum dolor sit amet consectetur asdasd ....
</div>
<div class="ml-5 flex-shrink-0">
<svg class="drop-shadow-custom w-5 h-5">
<use xlink:href="#filmmark"></use>
</svg>
</div>
</div>
<!-- e -->
</div>
</div>
</div>
</div>
</template>
<script>
import Dropdown from '@/Shared/Form/Dropdown'
import UserAvatar from '@/Shared/Misc/UserAvatar'
import AudioPlayer from '@/Shared/AudioPlayer'
export default {
components: {
AudioPlayer,
UserAvatar,
Dropdown,
}
}
</script>

View File

@@ -0,0 +1,42 @@
<template>
<div class="md:py-7 col-span-2 lg:col-span-1 border-r border-indigo-300">
<ul class="flex md:block text-base lg:text-xl xl:text-2xl text-gray-light overflow-x-auto">
<li
:class="[$page.component === 'Settings/SettingsProfile' ?
'md:border-l-4 md:border-b-0 border-b-2 border-pink text-white' :
'hover:text-white' ,'px-6 py-4']">
<inertia-link :href="route('setting.index')">Профиль</inertia-link>
</li>
<li
:class="[$page.url.startsWith('/settings/purchases') ?
'md:border-l-4 md:border-b-0 border-b-2 border-pink text-white' :
'hover:text-white' ,'px-6 py-4']">
<inertia-link :href="route('setting.purchases')">Покупки</inertia-link>
</li>
<li class="px-6 py-4 hover:text-white"><a href="#">Избранное</a></li>
<li
:class="[$page.component === 'Settings/SettingsMoney' ?
'md:border-l-4 md:border-b-0 border-b-2 border-pink text-white' :
'hover:text-white' ,'px-6 py-4']">
<inertia-link :href="route('setting.money')">Доход</inertia-link>
</li>
<li
:class="[$page.component === 'Settings/SettingsTarif' ?
'md:border-l-4 md:border-b-0 border-b-2 border-pink text-white' :
'hover:text-white' ,'px-6 py-4']">
<inertia-link :href="route('setting.tarif')">Тарифы</inertia-link>
</li>
<li
:class="[$page.component === 'Settings/SettingsNotify' ?
'md:border-l-4 md:border-b-0 border-b-2 border-pink text-white' :
'hover:text-white' ,'px-6 py-4']">
<inertia-link :href="route('setting.notify')">Оповещения</inertia-link>
</li>
<li class="px-6 py-4 hover:text-white"><a href="#">Сообщения</a></li>
</ul>
</div>
</template>

View File

@@ -0,0 +1,98 @@
<template>
<div class="hidden w-28 bg-indigo-200 overflow-y-auto md:block">
<div class="w-full py-6 flex flex-col items-center">
<div class="flex-1 w-full px-2 space-y-1">
<inertia-link :class="$page.url.startsWith('/profile') ? 'text-white group w-full p-3 rounded-md flex flex-col items-center text-xs font-medium' : 'text-gray-light hover:bg-orange hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs' " :href="route('profile.user', $page.props.auth.user.username)">
<svg :class="$page.url.startsWith('/profile') ? 'text-white h-6 w-6' : 'text-indigo-300 group-hover:text-white h-6 w-6' " xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
<span class="mt-2">Профиль</span>
</inertia-link>
<inertia-link :href="route('setting.money')"
class="lg:hidden text-gray-light hover:bg-orange hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs">
<svg class="text-green group-hover:text-white h-6 w-6" 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" ><line x1="12" y1="1" x2="12" y2="23"></line><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path></svg>
<span class="mt-2">{{$page.props.balance}}</span>
</inertia-link>
<a href="#"
class="relative text-gray-light hover:bg-orange hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs">
<div class="absolute top-1 right-1 w-2 h-2 md:w-5 md:h-5 bg-pink rounded-full text-xs flex justify-center items-center text-white">5</div>
<svg class="text-indigo-300 group-hover:text-white h-6 w-6" 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="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
<span class="mt-2">Сообщения</span>
</a>
<inertia-link :class="$page.component === 'Feed/Index' ? 'text-white group w-full p-3 rounded-md flex flex-col items-center text-xs font-medium' : 'text-gray-light hover:bg-orange hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs' " :href="route('feeds.layoutsidebar')">
<svg :class="$page.component === 'Feed/Index' ? 'text-white h-6 w-6' : 'text-indigo-300 group-hover:text-white h-6 w-6' " xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
</svg>
<span class="mt-2">Новости</span>
</inertia-link>
<inertia-link :class="$page.component === 'Image/Feed' ? 'text-white group w-full p-3 rounded-md flex flex-col items-center text-xs font-medium' : 'text-gray-light hover:bg-orange hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs' " :href="route('list.images')">
<svg :class="$page.component === 'Image/Feed' ? 'text-white h-6 w-6' : 'text-indigo-300 group-hover:text-white h-6 w-6' " xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<span class="mt-2">Изображения</span>
</inertia-link>
<inertia-link :class="$page.component === 'Video/Feed' ? 'text-white group w-full p-3 rounded-md flex flex-col items-center text-xs font-medium' : 'text-gray-light hover:bg-orange hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs' " :href="route('list.videos')">
<svg :class="$page.component === 'Video/Feed' ? 'text-white h-6 w-6' : 'text-indigo-300 group-hover:text-white h-6 w-6' " xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
<span class="mt-2">Видео</span>
</inertia-link>
<inertia-link :class="$page.component === 'Music/Feed' ? 'text-white group w-full p-3 rounded-md flex flex-col items-center text-xs font-medium' : 'text-gray-light hover:bg-orange hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs' " :href="route('list.musics')">
<svg :class="$page.component === 'Music/Feed' ? 'text-white h-6 w-6' : 'text-indigo-300 group-hover:text-white h-6 w-6' " xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3" />
</svg>
<span class="mt-2">Музыка</span>
</inertia-link>
<inertia-link :class="$page.component === 'User/Index' ? 'text-white group w-full p-3 rounded-md flex flex-col items-center text-xs font-medium' : 'text-gray-light hover:bg-orange hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs' " :href="route('users.index')">
<svg :class="$page.component === 'User/Index' ? 'text-white h-6 w-6' : 'text-indigo-300 group-hover:text-white h-6 w-6' " xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
<span class="mt-2">Пользователи</span>
</inertia-link>
<inertia-link :class="$page.component.startsWith('Settings') ? 'text-white group w-full p-3 rounded-md flex flex-col items-center text-xs font-medium' : 'text-gray-light hover:bg-orange hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs' " :href="route('setting.index')">
<svg :class="$page.component.startsWith('Settings') ? 'text-white h-6 w-6' : 'text-indigo-300 group-hover:text-white h-6 w-6' " xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<span class="mt-2">Настройки</span>
</inertia-link>
<inertia-link
as="button"
:href="route('logout')" method="delete"
class="relative text-gray-light hover:bg-orange hover:text-white group w-full p-3 rounded-md flex flex-col items-center text-xs">
<svg class="text-indigo-300 group-hover:text-white h-6 w-6" 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 stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" /></svg>
<span class="mt-2">Выйти</span>
</inertia-link>
</div>
</div>
</div>
</template>

View File

@@ -0,0 +1,27 @@
<template>
<section class="mt-16 hidden lg:w-[19rem] xl:w-[26rem] 2xl:w-[32rem] overflow-y-auto lg:block pr-5 2xl:pr-28">
<div class=" bg-indigo-200 shadow-classic rounded-md p-5">
<span class="block text-white font-medium">Лидеры</span>
<div class="mt-5 space-y-5">
<div class="flex items-center">
<div class="flex-shrink-0 mr-2 md:mr-4">
<div class="w-10 h-10 md:w-14 md:h-14 rounded-full bg-cover bg-center" style="background-image: url('/image/card1.jpg');"></div>
</div>
<div class="flex flex-col">
<a href="#" class="hover:underline text-sm md:text-base block text-white">Андрей Гаврилов</a>
<span class="text-xs text-gray-light">Фотограф, музыкант</span>
</div>
</div>
<div class="flex items-center">
<div class="flex-shrink-0 mr-2 md:mr-4">
<div class="w-10 h-10 md:w-14 md:h-14 rounded-full bg-cover bg-center" style="background-image: url('/image/card3.jpg');"></div>
</div>
<div class="flex flex-col">
<a href="#" class="hover:underline text-sm md:text-base block text-white">Владислав Сергеев</a>
<span class="text-xs text-gray-light">Дизайнер</span>
</div>
</div>
</div>
</div>
</section>
</template>

View File

@@ -0,0 +1,17 @@
<template>
<Head :title="title ? `${title} - Тизер` : 'Тизер'">
<slot />
</Head>
</template>
<script>
import { Head } from "@inertiajs/inertia-vue3";
export default {
components: {
Head,
},
props: {
title: String,
},
};
</script>

View File

@@ -0,0 +1,20 @@
<template>
<div class="flex items-center text-gray-light">
<svg class="w-5 h-5 flex-shrink-0">
<use xlink:href="#message-circle"></use>
</svg>
<span v-show="comments" class="ml-2 text-sm">{{
comments
}}</span>
</div>
</template>
<script>
export default {
components: {
},
props: {
comments: Number,
},
};
</script>

View File

@@ -0,0 +1,58 @@
<template>
<div>
<div v-if="$page.props.flash.success && show" class="mx-auto mt-4 mb-4 flex items-center justify-between bg-green rounded max-w-3xl">
<div class="flex items-center">
<svg class="ml-4 mr-2 flex-shrink-0 w-4 h-4 fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><polygon points="0 11 2 9 7 14 18 3 20 5 7 18" /></svg>
<div class="py-4 text-white text-sm font-medium">{{ $page.props.flash.success }}</div>
</div>
<button type="button" class="group mr-2 p-2" @click="show = false">
<svg class="block w-2 h-2 fill-green-800 group-hover:fill-white" xmlns="http://www.w3.org/2000/svg" width="235.908" height="235.908" viewBox="278.046 126.846 235.908 235.908"><path d="M506.784 134.017c-9.56-9.56-25.06-9.56-34.62 0L396 210.18l-76.164-76.164c-9.56-9.56-25.06-9.56-34.62 0-9.56 9.56-9.56 25.06 0 34.62L361.38 244.8l-76.164 76.165c-9.56 9.56-9.56 25.06 0 34.62 9.56 9.56 25.06 9.56 34.62 0L396 279.42l76.164 76.165c9.56 9.56 25.06 9.56 34.62 0 9.56-9.56 9.56-25.06 0-34.62L430.62 244.8l76.164-76.163c9.56-9.56 9.56-25.06 0-34.62z" /></svg>
</button>
</div>
<div v-if="($page.props.flash.error || Object.keys($page.props.errors).length > 0) && show" class="mx-auto mt-4 mb-4 flex items-center justify-between bg-red rounded max-w-3xl">
<div class="flex items-center">
<svg class="ml-4 mr-2 flex-shrink-0 w-4 h-4 fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm1.41-1.41A8 8 0 1 0 15.66 4.34 8 8 0 0 0 4.34 15.66zm9.9-8.49L11.41 10l2.83 2.83-1.41 1.41L10 11.41l-2.83 2.83-1.41-1.41L8.59 10 5.76 7.17l1.41-1.41L10 8.59l2.83-2.83 1.41 1.41z" /></svg>
<div v-if="$page.props.flash.error" class="py-4 text-white text-sm font-medium">{{ $page.props.flash.error }}</div>
<div v-else class="py-4 text-white text-sm font-medium">
<span v-if="Object.keys($page.props.errors).length === 1">There is one form error.</span>
<span v-else>There are {{ Object.keys($page.props.errors).length }} form errors.</span>
</div>
</div>
<button type="button" class="group mr-2 p-2" @click="show = false">
<svg class="block w-2 h-2 fill-red-800 group-hover:fill-white" xmlns="http://www.w3.org/2000/svg" width="235.908" height="235.908" viewBox="278.046 126.846 235.908 235.908"><path d="M506.784 134.017c-9.56-9.56-25.06-9.56-34.62 0L396 210.18l-76.164-76.164c-9.56-9.56-25.06-9.56-34.62 0-9.56 9.56-9.56 25.06 0 34.62L361.38 244.8l-76.164 76.165c-9.56 9.56-9.56 25.06 0 34.62 9.56 9.56 25.06 9.56 34.62 0L396 279.42l76.164 76.165c9.56 9.56 25.06 9.56 34.62 0 9.56-9.56 9.56-25.06 0-34.62L430.62 244.8l76.164-76.163c9.56-9.56 9.56-25.06 0-34.62z" /></svg>
</button>
</div>
</div>
</template>
<script>
//import { ref, watch } from 'vue'
export default {
// setup() {
// const show = ref(true)
// watch('$page.props.flash', function(){
// this.show = true
// });
// return {
// show,
// };
// },
data() {
return {
show: true,
}
},
watch: {
'$page.props.flash': {
handler() {
this.show = true
},
deep: true,
},
},
}
</script>

View File

@@ -0,0 +1,35 @@
<template>
<div
:class="[
liked ? 'text-red' : 'text-gray-light',
'flex items-center',
]"
>
<button @click.stop="likeFeed" class="default">
<svg class="w-5 h-5 flex-shrink-0">
<use xlink:href="#heart"></use>
</svg>
</button>
<span v-show="likes" class="ml-2 text-sm">{{
likes
}}</span>
</div>
</template>
<script>
export default {
components: {
},
emits:['likeFeed'],
props: {
likes: Number,
liked: Boolean,
},
methods:{
likeFeed(){
this.$emit('likeFeed');
}
}
};
</script>

View File

@@ -0,0 +1,20 @@
<template>
<div class="flex items-center text-gray-light">
<svg class="w-5 h-5 flex-shrink-0">
<use xlink:href="#share"></use>
</svg>
<span v-show="shares" class="ml-2 text-sm">{{
shares
}}</span>
</div>
</template>
<script>
export default {
components: {
},
props: {
shares: Number,
},
};
</script>

View File

@@ -0,0 +1,32 @@
<template>
<button :class="[ currentSong?.id === media_id ? '' : 'hidden', 'default' ]">
<svg :class="[ playing ? 'hidden' : 'block', 'w-6 h-6' ]">
<use xlink:href="#play"></use>
</svg>
<svg :class="[ playing ? 'block' : 'hidden', 'w-6 h-6' ]">
<use xlink:href="#pause"></use>
</svg>
</button>
<button :class="[ currentSong?.id !== media_id ? '' : 'hidden', 'default' ]">
<svg class="w-6 h-6">
<use xlink:href="#play"></use>
</svg>
</button>
</template>
<script>
import { mapState, mapGetters } from "vuex";
export default {
components: {
},
props: {
media_id: Number,
},
computed: {
...mapGetters(["playing"]),
...mapState({
currentSong: (state) => state.player.currentSong,
}),
},
};
</script>

View File

@@ -0,0 +1,31 @@
<template>
<div
v-if="user.photo_path"
class="rounded-full bg-cover bg-center"
:style="setBackground()"
></div>
<div
v-else
:style="`background-color:${user.color};`"
class="rounded-full font-bold flex items-center justify-center text-white"
>
{{ user.user_char }}
</div>
</template>
<script>
export default {
props: {
user: Object,
size: {
type: String,
default: 'small',
},
},
methods: {
setBackground() {
return `background-image: url(/img/${this.user.photo_path}?p=${this.size});`;
},
},
};
</script>

View File

@@ -0,0 +1,28 @@
<template>
<div
v-if="user.banner_path"
class="bg-cover bg-center"
:style="setBackground()"
></div>
<div
v-else
class="bg-cover bg-center"
></div>
</template>
<script>
export default {
props: {
user: Object,
size: {
type: String,
default: 'small',
},
},
methods: {
setBackground() {
return `background-image: url(/img/${this.user.banner_path}?p=${this.size});`;
},
},
};
</script>

View File

@@ -0,0 +1,10 @@
<template>
<div class="hidden">
<div class="flex items-center text-gray-light">
<span class="mr-2 text-sm">1030</span>
<svg class="w-5 h-5 flex-shrink-0">
<use xlink:href="#eye"></use>
</svg>
</div>
</div>
</template>

View File

@@ -0,0 +1,112 @@
<template>
<TransitionRoot as="template" :show="open">
<Dialog as="div" static class="fixed z-[1000] inset-0 overflow-y-auto" @close="staticCloseModal" :open="open">
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<TransitionChild as="template" enter="ease-out duration-300" enter-from="opacity-0" enter-to="opacity-100" leave="ease-in duration-200" leave-from="opacity-100" leave-to="opacity-0">
<DialogOverlay class="fixed inset-0 bg-indigo-200 bg-opacity-75 transition-opacity" />
</TransitionChild>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<TransitionChild as="template" enter="ease-out duration-300" enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enter-to="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-200" leave-from="opacity-100 translate-y-0 sm:scale-100" leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
<div class="inline-block align-bottom bg-indigo-300 md:rounded-md text-left overflow-hidden shadow-xl transform transition-all md:my-8 md:align-middle md:max-w-5xl w-full">
<div class="md:grid grid-cols-12">
<button @click="staticCloseModal" class="flex md:hidden w-full items-center justify-center p-3 bg-indigo-300 text-gray-light text-sm border-b border-indigo-100">Закрыть</button>
<modal-feed-media
:type='feed.type'
:feed_id='feed.id'
:title='feed.entity.title'
:preview='feed.entity.preview'
:medias='feed.entity.collection_medias'
/>
<modal-feed-body
@onRemoveFeed='onRemoveFeed'
@disableModal='checkCloseModal'
:user='feed.user'
:feed_id='feed.id'
:entity='feed.entity'
/>
</div>
</div>
</TransitionChild>
</div>
<modal-warning
@closeWarningModal="closeWarningModal"
@closeModal="staticCloseModal"
:feed_id='modalFeedId'
:open="warningShow"
/>
</Dialog>
</TransitionRoot>
</template>
<script>
import ModalWarning from "@/Shared/Overlay/ModalWarning";
import { Dialog, DialogOverlay, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'
import ModalFeedMedia from '@/Shared/Overlay/ModalFeedMedia'
import ModalFeedBody from '@/Shared/Overlay/ModalFeedBody'
export default {
components: {
Dialog,
DialogOverlay,
DialogTitle,
TransitionChild,
TransitionRoot,
ModalFeedMedia,
ModalFeedBody,
ModalWarning,
},
emits: ['onRemoveFeed', 'closeModal', 'destroyFeed'],
props: {
modalFeed: Object,
open: {
type: Boolean,
default: false,
},
},
data() {
return {
disabled: 0,
modalFeedId: 0,
warningShow: false,
feed: {}
}
},
watch: {
open(open){
if (open) {
this.feed = this.modalFeed;
}else{
}
}
},
methods: {
closeWarningModal()
{
this.warningShow = false;
this.$emit('destroyFeed');
},
onRemoveFeed(feed_id){
this.modalFeedId = feed_id;
this.warningShow = true;
},
checkCloseModal(value){
this.disabled = value;
},
staticCloseModal(){
if(!this.disabled){
this.$emit('closeModal', false);
}
},
}
}
</script>

View File

@@ -0,0 +1,224 @@
<template>
<div class="col-span-5 modal-body flex flex-col">
<div class="modal-head mb-3 px-2 py-4 md:py-4 md:px-6 flex justify-between items-center border-b border-indigo-100">
<div class="flex items-center space-x-4">
<inertia-link :href="route('profile.user', user.username)" class="flex-shrink-0 block">
<user-avatar :user='user' size='small' class="w-12 h-12 md:w-16 md:h-16 border-2 border-orange text-lg" />
</inertia-link>
<inertia-link :href="route('profile.user', user.username)" class="flex flex-col">
<p class="text-base md:text-xl font-semibold text-gray">{{user.name}}</p>
<p class="min-h-[24px]">
<span v-show="user.count_posts" class="md:mt-1 text-sm text-gray-light">{{user.count_posts}} {{countPosts}}</span>
</p>
</inertia-link>
</div>
<div class="text-white">
<dropdown-menu-point>
<MenuItems class="origin-top-right absolute right-0 mt-2 w-64 bg-indigo-200 shadow-lg max-h-60 rounded-md text-base ring-1 ring-indigo-100 overflow-auto focus:outline-none">
<MenuItem v-if="user.id === $page.props.auth.user.id">
<button @click="onRemoveFeed()" class="w-full group flex items-center px-4 py-2 text-base hover:bg-indigo-300 text-gray-light">
<MinusCircleIcon class="mr-3 h-5 w-5 text-gray-400 group-hover:text-orange" aria-hidden="true" />
Удалить
</button>
</MenuItem>
<MenuItem v-if="user.id !== $page.props.auth.user.id">
<inertia-link :href="route('video.create')" class="group flex items-center px-4 py-2 text-base hover:bg-indigo-300 text-gray-light">
<ExclamationIcon class="mr-3 h-5 w-5 text-gray-400 group-hover:text-orange" aria-hidden="true" />
Пожаловаться
</inertia-link>
</MenuItem>
</MenuItems>
</dropdown-menu-point>
</div>
</div>
<div data-simplebar class="modal-feed max-h-[29rem] overflow-auto">
<div class="p-2 md:py-4 md:px-6 space-y-3 md:space-y-6">
<div v-if="entity.body" class="comment-line comment-line--head flex flex-col text-gray text-sm">
<div class="flex group">
<inertia-link :href="route('profile.user', user.username)" class="flex-shrink-0 block mr-3">
<user-avatar :user='user' size='small' class="w-10 h-10 border border-orange text-xs" />
</inertia-link>
<div>
<inertia-link :href="route('profile.user', user.username)" class="font-semibold underline inline-block mr-2">
{{user.username}}
</inertia-link>
{{entity.body}}
<div class="transition-opacity opacity-0 group-hover:opacity-100 flex space-x-4">
<span class="text-xs text-gray-light">{{entity.created_at_humans}}</span>
</div>
</div>
</div>
</div>
<div v-for="comment in comments" :key='comment.id' class="comment-line flex flex-col text-gray text-sm">
<user-comment :creator_id='user.id' :comment='comment' />
</div>
</div>
</div>
<div class="modal-footer mt-auto p-2 md:py-4 md:px-6 border-t border-indigo-100">
<feed-paid-block
@onReplaceFeed='onReplaceFeed'
:is_paid='entity.is_paid'
:user_id='user.id'
:price='entity.price'
:feed_id='feed_id'
:paid_open='entity.paid_open'
class="text-white"
/>
<div class="misc-info mt-2 md:mt-0 mb-2 flex flex-row-reverse">
<div class="flex space-x-4">
<like-count @likeFeed='likeFeed' :likes='entity.likes' :liked='entity.liked' />
<comment-count :comments='entity.comments' />
<share-count />
</div>
<div class="mr-auto flex text-gray-light">
<button class="default">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-5 h-5 flex-shrink-0"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path></svg>
</button>
</div>
</div>
<div class="modal-send flex">
<div class="flex-1">
<textarea required v-model="new_comment" class="pl-0 pr-2 resize-none bg-indigo-300 w-full outline-none focus:ring-transparent focus:border-transparent focus:ring-offset-0 text-base text-gray border-transparent" placeholder="Написать комментарий..."></textarea>
</div>
<div class="mt-1 flex-shrink-0 text-pink">
<button @click="addComment" class="default">
<svg class="w-8 h-8 flex-shrink-0">
<use xlink:href="#arrow-circle"></use>
</svg>
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import { Inertia } from "@inertiajs/inertia";
import axios from "axios";
import helper from "@/includes/helper";
import DropdownMenuPoint from "@/Shared/Form/DropdownMenuPoint";
import { MenuItem, MenuItems } from "@headlessui/vue";
import { MinusCircleIcon, ExclamationIcon } from "@heroicons/vue/solid";
import FeedPaidBlock from "@/Shared/FeedList/FeedPaidBlock";
import UserAvatar from "@/Shared/Misc/UserAvatar";
import LikeCount from "@/Shared/Misc/LikeCount";
import CommentCount from "@/Shared/Misc/CommentCount";
import ShareCount from "@/Shared/Misc/ShareCount";
import UserComment from "@/Shared/Partials/UserComment";
export default {
components: {
DropdownMenuPoint,
MenuItem,
MenuItems,
MinusCircleIcon,
ExclamationIcon,
UserAvatar,
LikeCount,
ShareCount,
CommentCount,
UserComment,
FeedPaidBlock,
},
props: {
user: Object,
entity: Object,
feed_id: Number,
},
emits: ["disableModal", "onRemoveFeed"],
data() {
return {
new_comment: null,
comments: [],
};
},
mounted() {
console.log(this.entity)
this.loadComments();
this.loadCountPostsUser();
},
unmounted() {
this.comments = [];
},
computed: {
countPosts() {
return helper.declNumPosts(this.user.count_posts);
},
},
methods: {
onReplaceFeed(data) {
this.entity.collection_medias = data.collection;
this.entity.preview = data.preview;
this.entity.paid_open = 1;
},
loadCountPostsUser() {
if (
typeof this.user.count_posts === "undefined" ||
parseInt(this.user.count_posts, 10) === 0
) {
axios.post(route("user.posts.count", this.user.id)).then(({ data }) => {
this.user.count_posts = data;
});
}
},
onRemoveFeed() {
this.$emit("onRemoveFeed", this.feed_id);
},
loadComments() {
this.$emit("disableModal", 1);
axios.post(route("feed.comments", this.feed_id)).then(({ data }) => {
for (const prop in data) {
this.comments.push(data[prop]);
}
this.$emit("disableModal", 0);
});
},
addComment() {
this.$emit("disableModal", 1);
axios
.post(route("feed.comments.add", this.feed_id), {
body: this.new_comment,
})
.then(({ data }) => {
this.comments.push(data);
this.entity.comments++;
this.$emit("disableModal", 0);
});
this.new_comment = null;
},
likeFeed() {
Inertia.post(
route("feed.like", this.feed_id),
{},
{
preserveScroll: true,
preserveState: true,
}
);
if (this.entity.liked) {
this.entity.liked = false;
this.entity.likes--;
} else {
this.entity.liked = true;
this.entity.likes++;
}
},
},
};
</script>

View File

@@ -0,0 +1,37 @@
<template>
<div class="col-span-7 modal-media">
<component
:title="title"
:feed_id="feed_id"
:preview="preview"
:medias="medias"
:is="currentModalMedia"
></component>
</div>
</template>
<script>
import ModalFeedMediaImages from "@/Shared/Overlay/ModalFeedMediaImages";
import ModalFeedMediaVideos from "@/Shared/Overlay/ModalFeedMediaVideos";
import ModalFeedMediaMusics from "@/Shared/Overlay/ModalFeedMediaMusics";
export default {
components: {
ModalFeedMediaImages,
ModalFeedMediaVideos,
ModalFeedMediaMusics,
},
props: {
medias: Array,
type: String,
feed_id: Number,
title: String,
preview: String,
},
computed: {
currentModalMedia() {
return "modal-feed-media-" + this.type.toLowerCase();
},
},
methods: {},
};
</script>

View File

@@ -0,0 +1,33 @@
<template>
<swiper class="h-full" :grabCursor="true" navigation :pagination="{ clickable: true }">
<swiper-slide v-for="media in medias" :key="media.id">
<img class="w-full h-full object-cover" :src="media.url" alt="" />
</swiper-slide>
</swiper>
</template>
<script>
import SwiperCore, { Navigation, Pagination } from 'swiper/core';
import { Swiper, SwiperSlide } from "swiper/vue";
import "swiper/swiper-bundle.css";
// import "swiper/components/navigation/navigation.min.css";
// import "swiper/components/pagination/pagination.min.css";
SwiperCore.use([Navigation, Pagination]);
export default {
components: {
Swiper,
SwiperSlide,
},
props: {
medias: Array,
title: String,
preview: String,
},
methods: {},
};
</script>

View File

@@ -0,0 +1,87 @@
<template>
<div class="modal-media h-full border-r border-indigo-100">
<div class="flex items-center border-b border-indigo-100">
<div class="flex-shrink-0 mr-5">
<feed-preview
class="h-28 w-28 md:w-56 md:h-56 object-cover"
type="music"
:source="preview"
/>
</div>
<div class="flex flex-col">
<span class="text-base md:text-xl font-semibold text-gray">{{
title
}}</span>
</div>
</div>
<div data-simplebar class="max-h-72 overflow-auto">
<div class="divide-y divide-indigo-100">
<div
@click.prevent="startPlay(media)"
v-for="media in medias"
:key="media.id"
:class="[
currentSong?.id === media.id
? 'bg-indigo-200 bg-opacity-25'
: 'hover:bg-indigo-200 hover:bg-opacity-25',
'p-4 flex items-center space-x-4',
]"
>
<div class="flex">
<toggle-play-button :media_id="media.id" />
</div>
<div class="flex-1 text-sm text-gray-light">
{{ media.name }}
</div>
<div class="text-sm text-gray-light">
<div v-if="currentSong?.id === media.id">{{ seek }}</div>
<span v-else>{{ media.time }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions, mapState, mapGetters } from "vuex";
import FeedPreview from "@/Shared/Feed/FeedPreview";
import TogglePlayButton from "@/Shared/Misc/TogglePlayButton";
export default {
components: {
FeedPreview,
TogglePlayButton,
},
props: {
medias: Array,
title: String,
preview: String,
feed_id: Number,
},
methods: {
...mapActions(["toggleAudio", "newCurrentPlaylist", "skipToIndexByMusic"]),
startPlay(music) {
if (this.currentSong?.id === music.id) {
this.toggleAudio();
return;
}
// if (this.playlist_id === this.feed_id) {
// this.skipToIndexByMusic(music);
// return;
// }
this.newCurrentPlaylist([music, this.medias, this.feed_id]);
},
},
computed: {
...mapGetters(["playing"]),
...mapState({
playlist_id: (state) => state.player.playlist_id,
seek: (state) => state.player.seek,
currentSong: (state) => state.player.currentSong,
}),
},
};
</script>

View File

@@ -0,0 +1,32 @@
<template>
<swiper class="h-full" :grabCursor="true" navigation :pagination="{ clickable: true }">
<swiper-slide v-for="media in medias" class="aspect-w-16 aspect-h-12 md:aspect-h-9" :key="media.id">
<video :src="media.url" controls></video>
</swiper-slide>
</swiper>
</template>
<script>
import SwiperCore, { Navigation, Pagination } from 'swiper/core';
import { Swiper, SwiperSlide } from "swiper/vue";
import "swiper/swiper-bundle.css";
// import "swiper/components/navigation/navigation.min.css";
// import "swiper/components/pagination/pagination.min.css";
SwiperCore.use([Navigation, Pagination]);
export default {
components: {
Swiper,
SwiperSlide,
},
props: {
medias: Array,
title: String,
preview: String,
},
methods: {},
};
</script>

View File

@@ -0,0 +1,90 @@
<!-- This example requires Tailwind CSS v2.0+ -->
<template>
<TransitionRoot as="template" :show="open">
<Dialog as="div" static class="fixed z-[1000] inset-0 overflow-y-auto" @close="staticCloseModal" :open="open">
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<TransitionChild as="template" enter="ease-out duration-300" enter-from="opacity-0" enter-to="opacity-100" leave="ease-in duration-200" leave-from="opacity-100" leave-to="opacity-0">
<DialogOverlay class="fixed inset-0 bg-indigo-200 bg-opacity-75 transition-opacity" />
</TransitionChild>
<!-- This element is to trick the browser into centering the modal contents. -->
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<TransitionChild as="template" enter="ease-out duration-300" enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enter-to="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-200" leave-from="opacity-100 translate-y-0 sm:scale-100" leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
<div class="inline-block align-bottom bg-indigo-300 rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6">
<div class="sm:flex sm:items-start">
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-orange sm:mx-0 sm:h-10 sm:w-10">
<ExclamationIcon class="h-6 w-6 text-red-600" aria-hidden="true" />
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<DialogTitle as="h3" class="text-lg leading-6 font-medium text-gray-light">
Удалить контент
</DialogTitle>
<div class="mt-2">
<p class="text-sm text-gray-light">
Вы уверены, что хотите удалить этот контент? Восстановить можно, но будет сложно!
</p>
</div>
</div>
</div>
<div class="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<button type="button"
@click="remove"
class="mx-3 my-1 transition shadow-none hover:shadow-pink inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-pink focus:outline-none">
Удалить
</button>
<button type="button"
@click="staticCloseModal"
class="mx-3 my-1 transition shadow-none hover:shadow-classic inline-flex items-center px-8 py-3 justify-center text-base rounded-md text-white bg-indigo-300 focus:outline-none">
Отменить
</button>
</div>
</div>
</TransitionChild>
</div>
</Dialog>
</TransitionRoot>
</template>
<script>
import { Dialog, DialogOverlay, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'
import { ExclamationIcon } from '@heroicons/vue/outline'
import { Inertia } from "@inertiajs/inertia";
export default {
components: {
Dialog,
DialogOverlay,
DialogTitle,
TransitionChild,
TransitionRoot,
ExclamationIcon,
},
emits: ['closeWarningModal', 'closeModal', 'destroyFeed'],
props: {
feed_id: Number,
open: {
type: Boolean,
default: false,
},
},
methods:{
staticCloseModal(){
this.$emit('closeWarningModal', false);
},
remove()
{
this.$emit('closeWarningModal', false);
this.$nextTick(() => {
this.$emit('closeModal', false);
})
Inertia.delete(route('feed.destroy', this.feed_id), { preserveScroll: true, preserveState: true })
}
}
}
</script>

View File

@@ -0,0 +1,96 @@
<template>
<div class="gradient-profile relative">
<user-banner class="h-56 xl:h-80 bg-indigo-200" :user='user' size='hero' />
</div>
<div class="-mt-24 xl:-mt-32 relative xl:container xl:mx-auto px-2 md:px-3">
<div class="flex flex-col md:flex-row">
<div class="flex-shrink-0 self-center md:self-start md:mr-6 2xl:mr-10">
<user-avatar :user='user' size='medium' class="shadow-classic object-cover w-48 h-48 xl:w-64 xl:h-64 text-5xl" />
</div>
<div class="w-full">
<div class="h-24 xl:h-32 hidden md:block"></div>
<div class="mt-2 ">
<div class="-mx-2 -my-2 lg:-mx-4 lg:-my-4 flex flex-col md:flex-row flex-wrap xl:flex-nowrap">
<div class="max-w-[300px] text-center md:text-left mx-2 my-2 lg:mx-4 lg:my-4 flex flex-shrink-0 flex-col self-center md:self-start">
<h1 class="md:mb-3 text-2xl xl:text-4xl font-semibold text-white">{{ user.name }}</h1>
<h2 class="text-base xl:text-xl text-gray-light">@{{ user.username }}</h2>
</div>
<div class="mx-2 my-2 lg:mx-4 lg:my-4 self-center flex flex-1 flex-col">
<div class="md:mt-2">
<div class="flex 2xl:text-lg text-white -mx-4">
<inertia-link :href="route('profile.user', user.username)" class="block mx-4">
<span class="text-orange">{{counts.feeds}}</span> {{countPosts}}
</inertia-link>
<inertia-link :href="route('profile.subs', user.username)" class="block mx-4">
<span class="text-orange">{{counts.subscribers }}</span> {{countSubs}}
</inertia-link>
<inertia-link :href="route('profile.readers', user.username)" class="block mx-4">
<span class="text-orange">{{counts.readers}}</span> в читаемых
</inertia-link>
</div>
<div class="mt-4 text-gray-light text-sm">{{user.about}}</div>
</div>
</div>
<div class="mx-2 my-2 lg:mx-4 lg:my-4 2xl:flex-shrink-0 self-center text-center">
<inertia-link v-if="user.is_auth_user" class="inline-flex tracking-wide items-center px-4 py-3 border border-white text-sm 2xl:text-base text-white rounded-full bg-transparent hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2" :href="route('setting.index')">
Редактировать профиль
</inertia-link>
<toggle v-else
@clicked='susbscribe'
:user_id='user.id'
:enabled="user.is_sub"
textin='Подписаться' textout='Отписаться' />
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import UserAvatar from "@/Shared/Misc/UserAvatar";
import UserBanner from "@/Shared/Misc/UserBanner";
import Toggle from "@/Shared/Form/Toggle";
import helper from "@/includes/helper";
import { Inertia } from "@inertiajs/inertia";
export default {
components: {
Toggle,
UserAvatar,
UserBanner,
},
props: {
user: Object,
counts: Object,
},
computed: {
countPosts() {
return helper.declNumPosts(this.counts.posts);
},
countReaders() {
return helper.declNumReaders(this.counts.readers);
},
countSubs() {
return helper.declNumSubs(this.counts.subscribers);
},
},
methods: {
susbscribe(user_id) {
Inertia.post(
route("users.subs", user_id),
{},
{ preserveScroll: true, preserveState: true }
);
},
},
};
</script>

View File

@@ -0,0 +1,77 @@
<template>
<div class="mt-12 xl:container xl:mx-auto px-2 md:px-3 buttons-filter-line">
<div class="flex">
<div class="flex flex-wrap -mx-2 -my-2 lg:-mx-4 lg:-my-4">
<inertia-link :href="route('profile.user', user.username)"
:class="[$page.component === 'Profile/Index' ? 'shadow-classic2 bg-orange text-white' : 'shadow-classic text-gray bg-indigo-200 hover:bg-orange hover:text-white', 'mx-2 my-2 lg:mx-4 lg:my-4 py-3 px-6 xl:px-10 transition inline-flex items-center justify-center text-sm xl:text-base rounded-md focus:outline-none']">
<svg class="-ml-1 mr-2 h-4 w-4 md:h-5 md:w-5 flex-shrink-0" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.167 3.333a.833.833 0 00-.833.834v11.666c0 .46.373.834.833.834h11.667c.46 0 .833-.373.833-.834V4.167a.833.833 0 00-.833-.834H4.167zm-2.5.834a2.5 2.5 0 012.5-2.5h11.667a2.5 2.5 0 012.5 2.5v11.666a2.5 2.5 0 01-2.5 2.5H4.167a2.5 2.5 0 01-2.5-2.5V4.167z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M1.667 7.5c0-.46.373-.833.833-.833h15a.833.833 0 110 1.666h-15a.833.833 0 01-.833-.833z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M7.5 6.667c.46 0 .834.373.834.833v10a.833.833 0 01-1.667 0v-10c0-.46.373-.833.833-.833z"/></svg>
Публикации
</inertia-link>
<inertia-link :href="route('profile.readers', user.username)"
:class="[$page.component === 'Profile/Readers' ? 'shadow-classic2 bg-orange text-white' : 'shadow-classic text-gray bg-indigo-200 hover:bg-orange hover:text-white', 'mx-2 my-2 lg:mx-4 lg:my-4 py-3 px-6 xl:px-10 transition inline-flex items-center justify-center text-sm xl:text-base rounded-md focus:outline-none']">
<svg class="-ml-1 mr-2 h-4 w-4 md:h-5 md:w-5 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" 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-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><polyline points="17 11 19 13 23 9"></polyline></svg>
Читаемые
</inertia-link>
<inertia-link :href="route('profile.subs', user.username)"
:class="[$page.component === 'Profile/Subs' ? 'shadow-classic2 bg-orange text-white' : 'shadow-classic text-gray bg-indigo-200 hover:bg-orange hover:text-white', 'mx-2 my-2 lg:mx-4 lg:my-4 py-3 px-6 xl:px-10 transition inline-flex items-center justify-center text-sm xl:text-base rounded-md focus:outline-none']">
<svg class="-ml-1 mr-2 h-4 w-4 md:h-5 md:w-5 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" ><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
Подписчики
</inertia-link>
</div>
<div v-if="user.is_auth_user" class="ml-auto">
<dropdown-menu>
<MenuItems class="origin-top-right absolute right-0 mt-2 w-64 bg-indigo-300 shadow-lg max-h-60 rounded-md text-base ring-1 ring-indigo-200 overflow-auto focus:outline-none">
<MenuItem>
<inertia-link :href="route('video.create')" class="group flex items-center px-4 py-2 text-base hover:bg-indigo-200 text-gray-light">
<VideoCameraIcon class="mr-3 h-5 w-5 text-gray-400 group-hover:text-orange" aria-hidden="true" />
Загрузить видео
</inertia-link>
</MenuItem>
<MenuItem>
<inertia-link :href="route('image.create')" class="group flex items-center px-4 py-2 text-base hover:bg-indigo-200 text-gray-light">
<PhotographIcon class="mr-3 h-5 w-5 text-gray-400 group-hover:text-orange" aria-hidden="true" />
Загрузить изображение
</inertia-link>
</MenuItem>
<MenuItem>
<inertia-link :href="route('music.create')" class="group flex items-center px-4 py-2 text-base hover:bg-indigo-200 text-gray-light">
<MusicNoteIcon class="mr-3 h-5 w-5 text-gray-400 group-hover:text-orange" aria-hidden="true" />
Загрузить музыку
</inertia-link>
</MenuItem>
</MenuItems>
</dropdown-menu>
</div>
</div>
</div>
</template>
<script>
import {
PhotographIcon,
VideoCameraIcon,
MusicNoteIcon,
} from "@heroicons/vue/solid";
import { MenuItem, MenuItems } from "@headlessui/vue";
import DropdownMenu from "@/Shared/Form/DropdownMenu";
export default {
components: {
DropdownMenu,
MenuItem,
MenuItems,
PhotographIcon,
MusicNoteIcon,
VideoCameraIcon,
},
props: {
user: Object,
},
};
</script>

View File

@@ -0,0 +1,67 @@
<template>
<div class="flex group">
<inertia-link :href="route('profile.user', comment.user.username)" class="block flex-shrink-0 mr-3">
<user-avatar
:user="comment.user"
size="small"
:class="[
creator_id == comment.user.id ? 'border border-orange' : '',
'text-xs w-10 h-10',
]"
/>
</inertia-link>
<div class="flex-1 mr-3">
<inertia-link :href="route('profile.user', comment.user.username)" class="font-semibold underline inline-block mr-2">{{
comment.user.username
}}</inertia-link>
{{ comment.body }}
<div
class="
transition-opacity
opacity-0
group-hover:opacity-100
flex
space-x-4
"
>
<span class="text-xs text-gray-light">{{
comment.created_at_humans
}}</span>
<span
class="
text-xs text-gray-light
font-semibold
hover:underline
cursor-pointer
"
>ответить</span
>
</div>
</div>
<div class="flex-shrink-0">
<button class="button-default">
<svg class="w-3 h-3">
<use xlink:href="#heart"></use>
</svg>
</button>
</div>
</div>
</template>
<script>
import UserAvatar from '@/Shared/Misc/UserAvatar'
export default {
components: {
UserAvatar
},
props: {
comment: Object,
creator_id: Number,
},
methods:{
likeFeed(){
this.$emit('likeFeed');
}
}
};
</script>

View File

@@ -0,0 +1,38 @@
<template>
<section>
<h2 class="text-base text-gray font-semibold">Превью:</h2>
<div class="mt-3 grid grid-cols-2 sm:grid-cols-3 gap-2 lg:gap-4">
<div v-for="common_media in purchase.common_medias" :key="common_media.id">
<div data-fancybox="preview" :data-src="common_media.url" class="cursor-pointer">
<img :src="common_media.url" class="w-full h-36 md:h-72 object-cover" alt="">
</div>
<a :href="common_media.url" download class="hover:text-orange transition-colors mt-2 text-gray-light text-sm">Скачать</a>
</div>
</div>
</section>
<section class="mt-6">
<h2 class="text-base text-gray font-semibold">Медиа материалы:</h2>
<div class="mt-3 grid grid-cols-2 sm:grid-cols-3 gap-2 lg:gap-4">
<div v-for="paid_media in purchase.paid_medias" :key="paid_media.id">
<div data-fancybox="paid" :data-src="paid_media.url" class="cursor-pointer">
<img :src="paid_media.url" class="w-full h-36 md:h-72 object-cover" alt="">
</div>
<a :href="paid_media.url" download class="hover:text-orange transition-colors mt-2 text-gray-light text-sm">Скачать</a>
</div>
</div>
</section>
</template>
<script>
import { Fancybox } from "@fancyapps/ui/src/Fancybox/Fancybox.js";
import "@fancyapps/ui/dist/fancybox.css";
export default {
components: {},
props: {
purchase: Object,
},
};
</script>

View File

@@ -0,0 +1,38 @@
<template>
<section>
<h2 class="text-base text-gray font-semibold">Превью:</h2>
<div class="mt-3 ">
<feed-music-body
:feed_id='purchase.id'
:title='purchase.title'
:preview='purchase.preview'
:medias='purchase.common_medias'
/>
</div>
</section>
<section class="mt-6">
<h2 class="text-base text-gray font-semibold">Медиа материалы:</h2>
<div class="mt-3">
<feed-music-body
:feed_id='purchase.id'
:title='purchase.title'
:preview='purchase.preview'
:medias='purchase.paid_medias'
/>
</div>
</section>
</template>
<script>
import FeedMusicBody from "@/Shared/FeedList/FeedMusicBody";
export default {
components: {
FeedMusicBody,
},
props: {
purchase: Object,
},
};
</script>

View File

@@ -0,0 +1,73 @@
<template>
<div class="mt-2 p-2 lg:p-4">
<div class="relative">
<div class="absolute inset-y-0 left-3 flex items-center z-10">
<svg class="flex-shrink-0 h-5 w-5 text-gray-light" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" > <path fill-rule="evenodd" clip-rule="evenodd" d="M11 4a7 7 0 100 14 7 7 0 000-14zm-9 7a9 9 0 1118 0 9 9 0 01-18 0z"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M15.943 15.943a1 1 0 011.414 0l4.35 4.35a1 1 0 01-1.414 1.414l-4.35-4.35a1 1 0 010-1.414z"/> </svg>
</div>
<input class=" relative w-full focus:ring-4 focus:ring-offset-1 focus:ring-orange focus:ring-opacity-20 focus:ring-offset-orange focus:border-transparent text-gray border border-indigo-300 bg-indigo-200 rounded-md placeholder-gray-light !pl-10 " placeholder="Поиск музыки" type="search"/>
</div>
</div>
<div data-simplebar class="max-h-72 overflow-auto">
<div class="mt-2 divide-y divide-indigo-100">
<div
@click="toggleAudioLocal(listsMusic)"
v-for="listsMusic in listsMusics"
:key="listsMusic.id" class="
hover:bg-indigo-300 hover:bg-opacity-25 p-4 flex items-center space-x-4"
>
<div class="flex">
<button class="default">
<svg class="w-6 h-6">
<use v-show="!listsMusic.playing" xlink:href="#play"></use>
<use v-show="listsMusic.playing" xlink:href="#pause"></use>
</svg>
</button>
</div>
<div class="flex flex-1 text-sm text-gray-light">
{{ listsMusic.name }}
</div>
<div class="text-sm text-gray-light">
<span v-show="!listsMusic.playing">{{listsMusic.time}}</span>
<span v-show="listsMusic.playing">{{seek}}</span>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters, mapState } from "vuex";
export default {
components: {},
data() {
return {};
},
mounted() {
this.initLoadedPlaylist();
},
computed: {
...mapGetters(["tab_now"]),
...mapState({
seek: (state) => state.player.seek,
currentSong: (state) => state.player.currentSong,
listsMusics: (state) => state.player.playlist,
}),
},
methods: {
...mapActions(["initLoadedPlaylist", "toggleAudio", "skipToIndexByMusic"]),
toggleAudioLocal(music) {
if (this.tab_now && this.currentSong?.id === music.id) {
this.toggleAudio();
return;
}
this.skipToIndexByMusic(music);
},
},
};
</script>

View File

@@ -0,0 +1,72 @@
<template>
<div data-simplebar class="max-h-72 overflow-auto">
<div class="mt-2 divide-y divide-indigo-100">
<div
@click="toggleAudioLocal(listsMusic)"
v-for="listsMusic in listsMusics"
:key="listsMusic.id"
:class="[
currentSong?.id === listsMusic.id
? 'bg-indigo-300 bg-opacity-25'
: 'hover:bg-indigo-300 hover:bg-opacity-25',
'p-4 flex items-center space-x-4',
]"
>
<div class="flex">
<toggle-play-button :media_id="listsMusic.id" />
</div>
<div class="flex flex-1 text-sm text-gray-light">
{{ listsMusic.name }}
</div>
<div class="text-sm text-gray-light">
<span v-show="!listsMusic.playing">{{listsMusic.time}}</span>
<span v-show="listsMusic.playing">{{seek}}</span>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions, mapState } from "vuex";
import TogglePlayButton from "@/Shared/Misc/TogglePlayButton";
export default {
components: {
TogglePlayButton
},
data() {
return {
};
},
created(){
//console.log('loaded - now');
},
computed: {
//...mapGetters(["playing"]),
...mapState({
seek: (state) => state.player.seek,
currentSong: (state) => state.player.currentSong,
listsMusics: (state) => state.player.playlist,
}),
},
methods: {
...mapActions([
"toggleAudio",
"skipToIndexByMusic",
]),
toggleAudioLocal(music){
if (this.currentSong?.id === music.id) {
this.toggleAudio();
return;
}
this.skipToIndexByMusic(music);
},
},
};
</script>

25
resources/js/app.js vendored Normal file
View File

@@ -0,0 +1,25 @@
import { createApp, h } from 'vue'
import store from './store'
import { createInertiaApp, Link } from '@inertiajs/inertia-vue3'
import { InertiaProgress as progress } from '@inertiajs/progress'
progress.init({
color: '#673ab7',
})
createInertiaApp({
id: 'app',
resolve: name => import(`@/Pages/${name}`),
setup({ el, app, props, plugin }) {
createApp({ render: () => h(app, props) })
.mixin({
methods: {
route: window.route,
}
})
.use(store)
.use(plugin)
.component('InertiaLink', Link)
.mount(el)
},
})

24
resources/js/includes/helper.js vendored Normal file
View File

@@ -0,0 +1,24 @@
export default {
formatTime(time) {
var minutes = Math.floor(time / 60) || 0;
var seconds = Math.round((time - minutes * 60) || 0);
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
},
declOfNum (n, titles) {
return titles[n % 10 === 1 && n % 100 !== 11 ?
0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2];
},
declNumPosts(number){
const array_word = ['публикация', 'публикации', 'публикаций']
return this.declOfNum(number, array_word);
},
declNumReaders(number){
const array_word = ['публикация', 'публикации', 'публикаций']
return this.declOfNum(number, array_word);
},
declNumSubs(number){
const array_word = ['подписчик', 'подписчика', 'подписчиков']
return this.declOfNum(number, array_word);
}
};

6
resources/js/store/index.js vendored Normal file
View File

@@ -0,0 +1,6 @@
import { createStore } from 'vuex';
import modules from './modules';
export default createStore({
modules,
});

18
resources/js/store/modules/index.js vendored Normal file
View File

@@ -0,0 +1,18 @@
import { camelCase } from 'lodash';
const requireModule = require.context(
'.', false, /\.js$/,
);
const modules = {};
requireModule.keys().forEach((fileName) => {
if (fileName === './index.js' || fileName === './dummy.js') {
return;
}
const moduleConfig = requireModule(fileName);
const moduleName = camelCase(fileName.replace(/(\.\/|\.js)/g, ''));
modules[moduleName] = moduleConfig.default || moduleConfig;
});
export default modules;

273
resources/js/store/modules/player.js vendored Normal file
View File

@@ -0,0 +1,273 @@
import { Howl, Howler } from 'howler';
import axios from 'axios'
import helper from '@/includes/helper';
export default {
state: {
currentSong: {},
sound: {},
seek: '0:00',
duration: '0:00',
playerProgress: '0%',
playlist: [],
current_playlist: [],
my_playlist: [],
history_playlist: [],
playlist_id: 0,
history_group: [],
index: 0,
volume: 0.5,
tab: 'now',
local_current_playlist: JSON.parse(window.localStorage.getItem('local_current_playlist')),
local_current_playlist_song: JSON.parse(window.localStorage.getItem('local_current_playlist_song')),
local_current_playlist_id: parseInt(window.localStorage.getItem('local_current_playlist_id'), 10),
},
getters: {
playing: (state) => {
if (state.sound.playing) {
return state.sound.playing();
}
return false;
},
count_playlist: (state) => {
return state.playlist.length
},
volume_step: (state) => {
if (localStorage.volume_player) {
return localStorage.volume_player;
}
return state.volume
},
tab_now: (state) => {
return state.tab === 'now'
},
},
mutations: {
saveStorageCurrentPlaylist(state, [music, playlist, playlist_id]){
state.local_current_playlist = playlist;
state.local_current_playlist_song = music;
state.local_current_playlist_id = playlist_id;
window.localStorage.setItem('local_current_playlist', JSON.stringify(playlist));
window.localStorage.setItem('local_current_playlist_song', JSON.stringify(music));
window.localStorage.setItem('local_current_playlist_id', playlist_id);
},
clearPlaylist(state){
//state.playlist = [];
},
replaceTabName(state, payload){
state.tab = payload;
if(payload === 'now'){
state.playlist_id = state.local_current_playlist_id;
}else{
state.playlist_id = 0;
}
},
replacePlaylist(state, payload){
state.playlist = payload;
},
saveMyPlaylist(state, payload){
state.my_playlist = payload;
},
onlyPlay(state){
if (state.sound instanceof Howl) {
state.currentSong.playing = true;
state.sound.play();
}
},
onlyStop(state){
if (state.sound instanceof Howl) {
state.currentSong.playing = false;
state.sound.pause();
}
},
togglePlayMusic(state){
if (state.sound instanceof Howl) {
if (state.sound.playing()) {
state.currentSong.playing = false;
state.sound.pause();
} else {
state.currentSong.playing = true;
state.sound.play();
}
}
},
initVolume(state){
Howler.volume(state.volume);
},
updateVolume(state, payload) {
state.volume = payload;
localStorage.volume_player = payload;
if (state.sound instanceof Howl) {
Howler.volume(payload);
}
},
updatePosition(state) {
state.seek = helper.formatTime(state.sound.seek());
state.duration = helper.formatTime(state.sound.duration());
state.playerProgress = `${(state.sound.seek() / state.sound.duration()) * 100}%`;
},
currentPlaylistLoad(state, [music, playlist, playlist_id]){
playlist.forEach((track) => {
track.playing = false;
});
music.playing = true;
state.playlist = playlist;
state.playlist_id = playlist_id;
state.index = playlist.findIndex(track => track.id === music.id);
state.current_playlist = playlist;
},
howlReplace(state, [howl, music]){
if (state.sound instanceof Howl) {
state.sound.unload();
}
state.sound = howl;
state.currentSong = music;
state.index = state.playlist.findIndex(track => track.id === music.id);
},
},
actions: {
tabName({state, commit}, payload){
commit('replaceTabName', payload)
if(payload === 'loaded'){
if(state.my_playlist.length){
commit('replacePlaylist', state.my_playlist);
}
}
if(payload === 'now'){
if(state.current_playlist.length){
commit('replacePlaylist', state.current_playlist);
}
}
},
initLoadedPlaylist({state, commit}){
if(state.my_playlist.length > 0){
return;
}
return new Promise(resolve => {
commit('clearPlaylist');
axios.get(`/loaded-playlist`).then(response => response.data)
.then(playlist => {
commit('saveMyPlaylist', playlist);
commit('replacePlaylist', playlist);
commit('initVolume');
resolve(playlist)
})
.catch(() => {
//commit(mutationTypes.getArticleFailure)
})
})
},
async loadExsitPlaylist({ state, commit, dispatch }) {
if(state.local_current_playlist_id){
dispatch('instanceHowl', state.local_current_playlist_song);
commit('currentPlaylistLoad', [
state.local_current_playlist_song,
state.local_current_playlist,
state.local_current_playlist_id
]);
}
},
async skipToIndexByMusic({ state, commit, dispatch }, payload) {
commit('onlyStop');
dispatch('instanceHowl', payload);
commit('onlyPlay');
if(state.tab === 'now'){
commit('saveStorageCurrentPlaylist', [payload, state.playlist, state.playlist_id])
}
},
async newCurrentPlaylist({ commit, dispatch }, [music, playlist, playlist_id]){
commit('replaceTabName', 'now')
commit('onlyStop');
dispatch('instanceHowl', music);
commit('currentPlaylistLoad', [music, playlist, playlist_id]);
commit('initVolume');
commit('onlyPlay');
commit('saveStorageCurrentPlaylist', [music, playlist, playlist_id])
},
async instanceHowl({dispatch, commit}, payload){
let objectHowl = {};
objectHowl = new Howl({
src: [payload.url],
html5: true,
onend: () => {
dispatch('skipTrack', 'next');
}
});
objectHowl.on('play', () => {
requestAnimationFrame(() => {
dispatch('progress');
});
});
commit('howlReplace', [objectHowl, payload]);
},
async skipTrack({ state, dispatch }, payload) {
if (!state.playlist.length) {
return;
}
let index = 0;
if (payload === "next") {
index = state.index + 1
if (index >= state.playlist.length) {
index = 0
}
} else {
index = state.index - 1
if (index < 0) {
index = state.playlist.length - 1
}
}
dispatch('skipToIndexByMusic', state.playlist[index]);
},
async changeVolume({ commit }, payload) {
commit('updateVolume', payload);
},
async toggleAudio({ state, commit }) {
if (!state.sound.playing) {
return;
}
commit('togglePlayMusic');
},
progress({ commit, state, dispatch }) {
commit('updatePosition');
if (state.sound.playing()) {
requestAnimationFrame(() => {
dispatch('progress');
});
}
},
updateSeek({ state, dispatch }, payload) {
if (!state.sound.playing) {
return;
}
const { x, width } = payload.currentTarget.getBoundingClientRect();
// Document = 2000, Timeline = 1000, Click = 500, Distance = 500
const clickX = payload.clientX - x;
const percentage = clickX / width;
const seconds = state.sound.duration() * percentage;
state.sound.seek(seconds);
state.sound.once('seek', () => {
dispatch('progress');
});
},
},
};