- Added support for additional UI locales including Cebuano and Spanish, improving accessibility for a broader user base. - Updated language selection components in the AppHeader and SettingsWidget to reflect new language options, enhancing user experience. - Enhanced localization of various UI elements across components, ensuring consistent language representation and improved user engagement. - Implemented logic to synchronize user language preferences with backend settings, providing a seamless experience when changing languages.
650 lines
27 KiB
Vue
650 lines
27 KiB
Vue
<template>
|
||
<div class="contenthidden">
|
||
<div class="contentscroll">
|
||
<div class="erotic-videos-page">
|
||
<section class="erotic-videos-hero surface-card">
|
||
<div>
|
||
<span class="erotic-videos-eyebrow">{{ $t('socialnetwork.erotic.eyebrow') }}</span>
|
||
<h2>{{ isForeignView ? `${$t('socialnetwork.erotic.videosTitle')} · ${viewUsername}` : $t('socialnetwork.erotic.videosTitle') }}</h2>
|
||
<p>{{ isForeignView ? $t('socialnetwork.erotic.foreignVideosIntro') : $t('socialnetwork.erotic.videosIntro') }}</p>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="erotic-videos-workspace">
|
||
<aside class="erotic-videos-sidebar">
|
||
<section v-if="!isForeignView" class="erotic-videos-upload surface-card">
|
||
<div class="erotic-videos-upload__header">
|
||
<h3>{{ $t('socialnetwork.erotic.videoUploadTitle') }}</h3>
|
||
<p>{{ $t('socialnetwork.erotic.videoUploadHint') }}</p>
|
||
</div>
|
||
|
||
<form class="erotic-videos-form" @submit.prevent="handleUpload">
|
||
<label>
|
||
<span>{{ $t('socialnetwork.gallery.upload.image_title') }}</span>
|
||
<input v-model="title" type="text" :placeholder="$t('socialnetwork.gallery.upload.image_title')" />
|
||
</label>
|
||
<label>
|
||
<span>{{ $t('socialnetwork.erotic.videoDescription') }}</span>
|
||
<textarea v-model="description" rows="4" />
|
||
</label>
|
||
<label>
|
||
<span>{{ $t('socialnetwork.gallery.upload.visibility') }}</span>
|
||
<multiselect
|
||
v-model="selectedVisibilities"
|
||
:options="visibilityOptions"
|
||
:multiple="true"
|
||
:close-on-select="false"
|
||
label="description"
|
||
:placeholder="$t('socialnetwork.gallery.upload.selectvisibility')"
|
||
:track-by="'id'"
|
||
>
|
||
<template #option="{ option }">
|
||
<span v-if="option && option.description">
|
||
{{ $t(`socialnetwork.gallery.visibility.${option.description}`) }}
|
||
</span>
|
||
</template>
|
||
<template #tag="{ option, remove }">
|
||
<span v-if="option && option.description" class="multiselect__tag">
|
||
{{ $t(`socialnetwork.gallery.visibility.${option.description}`) }}
|
||
<span @click="remove(option)">×</span>
|
||
</span>
|
||
</template>
|
||
</multiselect>
|
||
</label>
|
||
<label v-if="requiresSelectedUsers">
|
||
<span>{{ $t('socialnetwork.gallery.visibility.selected-users') }}</span>
|
||
<input v-model="selectedUsernamesText" type="text" :placeholder="$t('socialnetwork.erotic.selectedUsersPlaceholder')" />
|
||
</label>
|
||
<label>
|
||
<span>{{ $t('socialnetwork.erotic.videoFile') }}</span>
|
||
<input type="file" accept="video/mp4,video/webm,video/ogg,video/quicktime" required @change="onFileChange" />
|
||
</label>
|
||
<div class="erotic-videos-upload__meta">
|
||
<span>{{ $t('socialnetwork.erotic.videoFormats') }}</span>
|
||
<span v-if="fileToUpload">{{ fileToUpload.name }}</span>
|
||
</div>
|
||
<button type="submit">{{ $t('socialnetwork.gallery.upload.upload_button') }}</button>
|
||
</form>
|
||
</section>
|
||
|
||
<section class="erotic-videos-panel surface-card">
|
||
<h3>{{ $t('socialnetwork.erotic.libraryTitle') }}</h3>
|
||
<div class="erotic-videos-panel__list">
|
||
<div class="erotic-videos-panel__item">
|
||
<span>{{ isForeignView ? $t('socialnetwork.erotic.sharedVideos') : $t('socialnetwork.erotic.myVideos') }}</span>
|
||
<strong>{{ videos.length }}</strong>
|
||
</div>
|
||
<div class="erotic-videos-panel__item">
|
||
<span>{{ $t('socialnetwork.erotic.latestUpload') }}</span>
|
||
<strong>{{ latestVideoTitle }}</strong>
|
||
</div>
|
||
<div class="erotic-videos-panel__item">
|
||
<span>{{ $t('socialnetwork.erotic.visibleVideos') }}</span>
|
||
<strong>{{ visibleVideosCount }}</strong>
|
||
</div>
|
||
<div class="erotic-videos-panel__item">
|
||
<span>{{ $t('socialnetwork.erotic.moderationCases') }}</span>
|
||
<strong>{{ hiddenVideosCount }}</strong>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="erotic-videos-panel surface-card">
|
||
<h3>{{ $t('socialnetwork.erotic.notesTitle') }}</h3>
|
||
<ul class="erotic-videos-checklist">
|
||
<li>{{ isForeignView ? $t('socialnetwork.erotic.foreignVideosOnlyHint') : $t('socialnetwork.erotic.videoUploadHint') }}</li>
|
||
<li>{{ $t('socialnetwork.erotic.friendsVisibilityHint') }}</li>
|
||
<li>{{ $t('socialnetwork.erotic.selectedUsersVisibilityHint') }}</li>
|
||
<li>{{ $t('socialnetwork.erotic.reportHint', { action: $t('socialnetwork.erotic.reportAction') }) }}</li>
|
||
</ul>
|
||
</section>
|
||
</aside>
|
||
|
||
<section class="erotic-videos-library surface-card">
|
||
<div class="erotic-videos-library__header">
|
||
<div>
|
||
<h3>{{ isForeignView ? $t('socialnetwork.erotic.sharedVideos') : $t('socialnetwork.erotic.myVideos') }}</h3>
|
||
<p>{{ isForeignView ? $t('socialnetwork.erotic.sharedVideosIntro') : $t('socialnetwork.erotic.libraryIntro') }}</p>
|
||
</div>
|
||
<span class="erotic-videos-library__count">{{ videos.length }}</span>
|
||
</div>
|
||
|
||
<div v-if="videos.length === 0" class="erotic-videos-empty">
|
||
<strong>{{ $t('socialnetwork.erotic.noVideos') }}</strong>
|
||
<span>{{ isForeignView ? $t('socialnetwork.erotic.noSharedVideos') : $t('socialnetwork.erotic.libraryEmptyHint') }}</span>
|
||
</div>
|
||
|
||
<div v-else class="erotic-videos-library__scroll">
|
||
<ul class="erotic-videos-grid">
|
||
<li v-for="video in videos" :key="video.id" class="erotic-videos-card">
|
||
<video v-if="!video.isModeratedHidden" :src="video.url" controls preload="metadata" />
|
||
<div v-else class="erotic-videos-card__hidden">
|
||
{{ $t('socialnetwork.erotic.hiddenByModeration') }}
|
||
</div>
|
||
<div class="erotic-videos-card__meta">
|
||
<strong>{{ video.title || $t('socialnetwork.erotic.untitled') }}</strong>
|
||
<span v-if="video.createdAtLabel">{{ video.createdAtLabel }}</span>
|
||
</div>
|
||
<div v-if="video.visibilities?.length" class="erotic-videos-card__visibility">
|
||
<span v-for="visibility in video.visibilities" :key="`${video.id}-${visibility.id}`" class="erotic-videos-card__visibility-badge">
|
||
{{ $t(`socialnetwork.gallery.visibility.${visibility.description}`) }}
|
||
</span>
|
||
</div>
|
||
<span v-if="video.isModeratedHidden" class="erotic-videos-card__badge">
|
||
{{ $t('socialnetwork.erotic.moderationHidden') }}
|
||
</span>
|
||
<p v-if="video.description">{{ video.description }}</p>
|
||
<div v-if="!isForeignView" class="erotic-videos-card__edit">
|
||
<button type="button" class="secondary" @click="toggleEditor(video.id)">
|
||
{{ editingVideoId === video.id ? $t('socialnetwork.erotic.closeEditing') : $t('socialnetwork.erotic.editVisibility') }}
|
||
</button>
|
||
<div v-if="editingVideoId === video.id" class="erotic-videos-editor">
|
||
<label>
|
||
<span>{{ $t('socialnetwork.gallery.upload.image_title') }}</span>
|
||
<input v-model="editForm.title" type="text" />
|
||
</label>
|
||
<label>
|
||
<span>{{ $t('socialnetwork.erotic.videoDescription') }}</span>
|
||
<textarea v-model="editForm.description" rows="3" />
|
||
</label>
|
||
<label>
|
||
<span>{{ $t('socialnetwork.gallery.upload.visibility') }}</span>
|
||
<multiselect
|
||
v-model="editForm.visibilities"
|
||
:options="visibilityOptions"
|
||
:multiple="true"
|
||
:close-on-select="false"
|
||
label="description"
|
||
:placeholder="$t('socialnetwork.gallery.upload.selectvisibility')"
|
||
:track-by="'id'"
|
||
>
|
||
<template #option="{ option }">
|
||
<span v-if="option && option.description">
|
||
{{ $t(`socialnetwork.gallery.visibility.${option.description}`) }}
|
||
</span>
|
||
</template>
|
||
<template #tag="{ option, remove }">
|
||
<span v-if="option && option.description" class="multiselect__tag">
|
||
{{ $t(`socialnetwork.gallery.visibility.${option.description}`) }}
|
||
<span @click="remove(option)">×</span>
|
||
</span>
|
||
</template>
|
||
</multiselect>
|
||
</label>
|
||
<label v-if="editRequiresSelectedUsers">
|
||
<span>{{ $t('socialnetwork.gallery.visibility.selected-users') }}</span>
|
||
<input v-model="editForm.selectedUsernamesText" type="text" :placeholder="$t('socialnetwork.erotic.selectedUsersPlaceholder')" />
|
||
</label>
|
||
<div class="erotic-videos-editor__actions">
|
||
<button type="button" @click="saveVideo(video.id)">{{ $t('common.save') }}</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="erotic-videos-card__actions">
|
||
<button type="button" class="secondary" @click="startReport('video', video.id)">
|
||
{{ $t('socialnetwork.erotic.reportAction') }}
|
||
</button>
|
||
</div>
|
||
<div v-if="reportTarget.type === 'video' && reportTarget.id === video.id" class="erotic-report-form">
|
||
<select v-model="reportReason">
|
||
<option v-for="option in reportReasonOptions" :key="option.value" :value="option.value">
|
||
{{ option.label }}
|
||
</option>
|
||
</select>
|
||
<textarea v-model="reportNote" rows="3" :placeholder="$t('socialnetwork.erotic.reportNote')" />
|
||
<div class="erotic-report-form__actions">
|
||
<button type="button" @click="submitReport">{{ $t('socialnetwork.erotic.submitReport') }}</button>
|
||
<button type="button" class="secondary" @click="resetReport">{{ $t('general.cancel') }}</button>
|
||
</div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import apiClient from '@/utils/axios.js';
|
||
import Multiselect from 'vue-multiselect';
|
||
import 'vue-multiselect/dist/vue-multiselect.min.css';
|
||
import { mapGetters } from 'vuex';
|
||
import { showApiError, showSuccess } from '@/utils/feedback.js';
|
||
|
||
export default {
|
||
name: 'EroticVideosView',
|
||
components: {
|
||
Multiselect
|
||
},
|
||
data() {
|
||
return {
|
||
videos: [],
|
||
fileToUpload: null,
|
||
title: '',
|
||
description: '',
|
||
visibilityOptions: [],
|
||
selectedVisibilities: [],
|
||
selectedUsernamesText: '',
|
||
editingVideoId: null,
|
||
editForm: {
|
||
title: '',
|
||
description: '',
|
||
visibilities: [],
|
||
selectedUsernamesText: ''
|
||
},
|
||
reportTarget: { type: null, id: null },
|
||
reportReason: 'other',
|
||
reportNote: '',
|
||
viewUsername: ''
|
||
};
|
||
},
|
||
computed: {
|
||
...mapGetters(['user']),
|
||
reportReasonOptions() {
|
||
return ['suspected_minor', 'non_consensual', 'violence', 'harassment', 'spam', 'other'].map(value => ({
|
||
value,
|
||
label: this.$t(`socialnetwork.erotic.reportReasons.${value}`)
|
||
}));
|
||
},
|
||
isForeignView() {
|
||
return Boolean(this.viewUsername && this.viewUsername !== this.user?.username);
|
||
},
|
||
requiresSelectedUsers() {
|
||
return this.selectedVisibilities.some(option => option?.description === 'selected-users');
|
||
},
|
||
editRequiresSelectedUsers() {
|
||
return this.editForm.visibilities.some(option => option?.description === 'selected-users');
|
||
},
|
||
visibleVideosCount() {
|
||
return this.videos.filter((video) => !video.isModeratedHidden).length;
|
||
},
|
||
hiddenVideosCount() {
|
||
return this.videos.filter((video) => video.isModeratedHidden).length;
|
||
},
|
||
latestVideoTitle() {
|
||
return this.videos[0]?.title || this.$t('socialnetwork.erotic.noUploadYet');
|
||
}
|
||
},
|
||
async mounted() {
|
||
await this.initializeView();
|
||
await this.loadImageVisibilities();
|
||
},
|
||
beforeUnmount() {
|
||
this.releaseVideoUrls();
|
||
},
|
||
methods: {
|
||
async initializeView() {
|
||
this.viewUsername = String(this.$route.query.username || '').trim();
|
||
await this.loadVideos();
|
||
},
|
||
async loadImageVisibilities() {
|
||
const response = await apiClient.get('/api/socialnetwork/imagevisibilities');
|
||
this.visibilityOptions = response.data.filter(option => option.description !== 'everyone');
|
||
if (!this.selectedVisibilities.length) {
|
||
this.selectedVisibilities = this.visibilityOptions.filter(option => option.description === 'adults');
|
||
}
|
||
},
|
||
async loadVideos() {
|
||
this.releaseVideoUrls();
|
||
const response = this.isForeignView
|
||
? await apiClient.get(`/api/socialnetwork/profile/erotic/videos/${this.viewUsername}`)
|
||
: await apiClient.get('/api/socialnetwork/erotic/videos');
|
||
this.videos = await Promise.all(response.data.map(async (video) => ({
|
||
...video,
|
||
url: video.isModeratedHidden ? null : await this.fetchVideoUrl(video.hash),
|
||
createdAtLabel: video.createdAt ? new Date(video.createdAt).toLocaleDateString() : '',
|
||
})));
|
||
},
|
||
releaseVideoUrls() {
|
||
this.videos.forEach((video) => {
|
||
if (video?.url) {
|
||
URL.revokeObjectURL(video.url);
|
||
}
|
||
});
|
||
},
|
||
async fetchVideoUrl(hash) {
|
||
const response = await apiClient.get(`/api/socialnetwork/erotic/video/${hash}`, {
|
||
responseType: 'blob',
|
||
});
|
||
return URL.createObjectURL(response.data);
|
||
},
|
||
onFileChange(event) {
|
||
this.fileToUpload = event.target.files[0];
|
||
},
|
||
async handleUpload() {
|
||
if (!this.fileToUpload) return;
|
||
const formData = new FormData();
|
||
formData.append('video', this.fileToUpload);
|
||
formData.append('title', this.title);
|
||
formData.append('description', this.description);
|
||
formData.append('visibility', JSON.stringify(this.selectedVisibilities.map((visibility) => visibility.id)));
|
||
formData.append('selectedUsers', JSON.stringify(
|
||
this.selectedUsernamesText.split(',').map(value => value.trim()).filter(Boolean)
|
||
));
|
||
await apiClient.post('/api/socialnetwork/erotic/videos', formData, {
|
||
headers: { 'Content-Type': 'multipart/form-data' }
|
||
});
|
||
this.fileToUpload = null;
|
||
this.title = '';
|
||
this.description = '';
|
||
this.selectedUsernamesText = '';
|
||
this.selectedVisibilities = this.visibilityOptions.filter(option => option.description === 'adults');
|
||
await this.loadVideos();
|
||
},
|
||
toggleEditor(videoId) {
|
||
if (this.editingVideoId === videoId) {
|
||
this.editingVideoId = null;
|
||
return;
|
||
}
|
||
const video = this.videos.find(entry => entry.id === videoId);
|
||
if (!video) return;
|
||
this.editingVideoId = videoId;
|
||
this.editForm = {
|
||
title: video.title || '',
|
||
description: video.description || '',
|
||
visibilities: this.visibilityOptions.filter(option =>
|
||
(video.visibilities || []).some(visibility => visibility.id === option.id)
|
||
),
|
||
selectedUsernamesText: (video.selectedUsers || []).join(', ')
|
||
};
|
||
},
|
||
async saveVideo(videoId) {
|
||
await apiClient.put(`/api/socialnetwork/erotic/videos/${videoId}`, {
|
||
title: this.editForm.title,
|
||
description: this.editForm.description,
|
||
visibilities: this.editForm.visibilities,
|
||
selectedUsers: this.editForm.selectedUsernamesText.split(',').map(value => value.trim()).filter(Boolean)
|
||
});
|
||
this.editingVideoId = null;
|
||
await this.loadVideos();
|
||
},
|
||
startReport(type, id) {
|
||
this.reportTarget = { type, id };
|
||
this.reportReason = 'other';
|
||
this.reportNote = '';
|
||
},
|
||
resetReport() {
|
||
this.reportTarget = { type: null, id: null };
|
||
this.reportReason = 'other';
|
||
this.reportNote = '';
|
||
},
|
||
async submitReport() {
|
||
try {
|
||
await apiClient.post('/api/socialnetwork/erotic/report', {
|
||
targetType: this.reportTarget.type,
|
||
targetId: this.reportTarget.id,
|
||
reason: this.reportReason,
|
||
note: this.reportNote
|
||
});
|
||
showSuccess(this, this.$t('socialnetwork.erotic.reportSubmitted'));
|
||
this.resetReport();
|
||
} catch (error) {
|
||
showApiError(this, error, this.$t('socialnetwork.erotic.reportError'));
|
||
}
|
||
}
|
||
},
|
||
watch: {
|
||
'$route.query.username': {
|
||
async handler() {
|
||
await this.initializeView();
|
||
}
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.erotic-videos-page {
|
||
display: grid;
|
||
gap: 1.25rem;
|
||
padding-bottom: 1.25rem;
|
||
}
|
||
|
||
.erotic-videos-hero,
|
||
.erotic-videos-upload,
|
||
.erotic-videos-library,
|
||
.erotic-videos-panel {
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-soft);
|
||
}
|
||
|
||
.erotic-videos-hero {
|
||
padding: 1.4rem 1.5rem;
|
||
}
|
||
|
||
.erotic-videos-eyebrow {
|
||
display: inline-flex;
|
||
margin-bottom: 0.5rem;
|
||
padding: 0.25rem 0.7rem;
|
||
border-radius: 999px;
|
||
background: rgba(120, 195, 138, 0.14);
|
||
color: #42634e;
|
||
font-size: 0.78rem;
|
||
font-weight: 700;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.erotic-videos-hero p {
|
||
margin: 0;
|
||
color: var(--color-text-secondary);
|
||
}
|
||
|
||
.erotic-videos-workspace {
|
||
display: grid;
|
||
grid-template-columns: minmax(280px, 340px) minmax(0, 1fr);
|
||
gap: 1.25rem;
|
||
min-height: min(72vh, 860px);
|
||
}
|
||
|
||
.erotic-videos-sidebar {
|
||
display: grid;
|
||
gap: 1rem;
|
||
align-content: start;
|
||
min-height: 0;
|
||
}
|
||
|
||
.erotic-videos-upload,
|
||
.erotic-videos-library,
|
||
.erotic-videos-panel {
|
||
padding: 1.25rem;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.erotic-videos-upload__header,
|
||
.erotic-videos-form {
|
||
display: grid;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.erotic-videos-form label,
|
||
.erotic-videos-editor label {
|
||
display: grid;
|
||
gap: 0.35rem;
|
||
}
|
||
|
||
.erotic-videos-upload__meta {
|
||
display: grid;
|
||
gap: 0.25rem;
|
||
color: var(--color-text-secondary);
|
||
font-size: 0.82rem;
|
||
}
|
||
|
||
.erotic-videos-panel {
|
||
display: grid;
|
||
gap: 0.9rem;
|
||
}
|
||
|
||
.erotic-videos-panel__list,
|
||
.erotic-videos-checklist {
|
||
display: grid;
|
||
gap: 0.7rem;
|
||
}
|
||
|
||
.erotic-videos-panel__item {
|
||
display: grid;
|
||
gap: 0.15rem;
|
||
padding: 0.75rem 0.85rem;
|
||
border-radius: var(--radius-md);
|
||
background: rgba(112, 60, 80, 0.06);
|
||
}
|
||
|
||
.erotic-videos-panel__item span,
|
||
.erotic-videos-checklist {
|
||
color: var(--color-text-secondary);
|
||
}
|
||
|
||
.erotic-videos-checklist {
|
||
margin: 0;
|
||
padding-left: 1.1rem;
|
||
}
|
||
|
||
.erotic-videos-library {
|
||
display: grid;
|
||
grid-template-rows: auto minmax(0, 1fr);
|
||
gap: 1rem;
|
||
min-height: 0;
|
||
}
|
||
|
||
.erotic-videos-library__header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 1rem;
|
||
align-items: start;
|
||
}
|
||
|
||
.erotic-videos-library__header p {
|
||
margin: 0.3rem 0 0;
|
||
color: var(--color-text-secondary);
|
||
}
|
||
|
||
.erotic-videos-library__count {
|
||
display: inline-flex;
|
||
min-width: 2.2rem;
|
||
min-height: 2.2rem;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 999px;
|
||
background: rgba(112, 60, 80, 0.08);
|
||
font-weight: 800;
|
||
}
|
||
|
||
.erotic-videos-library__scroll {
|
||
min-height: 0;
|
||
overflow: auto;
|
||
padding-right: 0.2rem;
|
||
}
|
||
|
||
.erotic-videos-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||
gap: 1rem;
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.erotic-videos-card {
|
||
display: grid;
|
||
gap: 0.5rem;
|
||
padding: 0.85rem;
|
||
border-radius: var(--radius-md);
|
||
background: rgba(112, 60, 80, 0.08);
|
||
}
|
||
|
||
.erotic-videos-card__meta {
|
||
display: grid;
|
||
gap: 0.2rem;
|
||
}
|
||
|
||
.erotic-videos-card__meta span {
|
||
color: var(--color-text-secondary);
|
||
font-size: 0.82rem;
|
||
}
|
||
|
||
.erotic-videos-card__visibility {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.35rem;
|
||
}
|
||
|
||
.erotic-videos-card__visibility-badge {
|
||
display: inline-flex;
|
||
padding: 0.2rem 0.55rem;
|
||
border-radius: var(--radius-pill);
|
||
background: rgba(66, 99, 78, 0.12);
|
||
color: #42634e;
|
||
font-size: 0.74rem;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.erotic-videos-card__hidden {
|
||
display: grid;
|
||
place-items: center;
|
||
min-height: 160px;
|
||
border-radius: var(--radius-sm);
|
||
background: rgba(96, 32, 48, 0.18);
|
||
color: var(--color-text-secondary);
|
||
text-align: center;
|
||
padding: 1rem;
|
||
}
|
||
|
||
.erotic-videos-card__badge {
|
||
display: inline-flex;
|
||
width: fit-content;
|
||
padding: 0.2rem 0.65rem;
|
||
border-radius: var(--radius-pill);
|
||
background: rgba(176, 88, 88, 0.14);
|
||
color: #8b3340;
|
||
font-size: 0.78rem;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.erotic-videos-card video {
|
||
width: 100%;
|
||
border-radius: var(--radius-sm);
|
||
background: #120b0f;
|
||
}
|
||
|
||
.erotic-videos-card__actions,
|
||
.erotic-videos-card__edit,
|
||
.erotic-videos-editor,
|
||
.erotic-videos-editor__actions,
|
||
.erotic-report-form,
|
||
.erotic-report-form__actions {
|
||
display: grid;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.erotic-videos-empty {
|
||
display: grid;
|
||
gap: 0.35rem;
|
||
place-items: center;
|
||
min-height: 240px;
|
||
padding: 1.5rem;
|
||
text-align: center;
|
||
color: var(--color-text-secondary);
|
||
background: rgba(112, 60, 80, 0.05);
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
@media (max-width: 980px) {
|
||
.erotic-videos-workspace {
|
||
grid-template-columns: 1fr;
|
||
min-height: auto;
|
||
}
|
||
|
||
.erotic-videos-library {
|
||
grid-template-rows: auto auto;
|
||
}
|
||
|
||
.erotic-videos-library__scroll {
|
||
overflow: visible;
|
||
}
|
||
}
|
||
</style>
|