add new marking-content layout
This commit is contained in:
@@ -4,6 +4,8 @@ import PageTitle from '@/app/ui/page-title';
|
||||
import UploadSectionFile from '@/app/components/upload-section-file';
|
||||
import { getAllowedFilesExtensions } from '@/app/actions/fileUpload';
|
||||
import { StackedBarChart } from '@/app/components/StackedBarChart';
|
||||
import PageTitleColorFrame from '@/app/ui/page-title-color-frame';
|
||||
import ProtectionStatistic from '@/app/ui/marking-page/new/protection-statistic';
|
||||
|
||||
const data = [
|
||||
{
|
||||
@@ -44,9 +46,13 @@ export default async function Page() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageTitle title="audio-protection" />
|
||||
<PageTitleColorFrame
|
||||
title="audio-protection"
|
||||
description="multi-layered-protection-for-your-audios"
|
||||
/>
|
||||
<ProtectionStatistic fileType={FILE_TYPE} />
|
||||
<div className="split-blocks">
|
||||
<ProtectionSummary fileType={FILE_TYPE}/>
|
||||
<ProtectionSummary fileType={FILE_TYPE} />
|
||||
<div className="protection-overview">
|
||||
<StackedBarChart data={data} />
|
||||
</div>
|
||||
|
||||
@@ -3,8 +3,10 @@ import FilesTable from '@/app/ui/dashboard/files-table';
|
||||
import PageTitle from '@/app/ui/page-title';
|
||||
import UploadSectionFile from '@/app/components/upload-section-file';
|
||||
import { getAllowedFilesExtensions } from '@/app/actions/fileUpload';
|
||||
import {StackedBarChart} from '@/app/components/StackedBarChart';
|
||||
import {TestComponent} from '@/app/components/test-component';
|
||||
import { StackedBarChart } from '@/app/components/StackedBarChart';
|
||||
import { TestComponent } from '@/app/components/test-component';
|
||||
import PageTitleColorFrame from '@/app/ui/page-title-color-frame';
|
||||
import ProtectionStatistic from '@/app/ui/marking-page/new/protection-statistic';
|
||||
|
||||
const data = [
|
||||
{
|
||||
@@ -40,10 +42,14 @@ export default async function Page() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageTitle title="image-protection" />
|
||||
<TestComponent/>
|
||||
<PageTitleColorFrame
|
||||
title="image-protection"
|
||||
description="multi-layered-protection-for-your-images"
|
||||
/>
|
||||
<TestComponent />
|
||||
<ProtectionStatistic fileType={FILE_TYPE}/>
|
||||
<div className="split-blocks">
|
||||
<ProtectionSummary fileType={FILE_TYPE}/>
|
||||
<ProtectionSummary fileType={FILE_TYPE} />
|
||||
<div className="protection-overview">
|
||||
<StackedBarChart data={data} />
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,8 @@ import PageTitle from '@/app/ui/page-title';
|
||||
import UploadSectionFile from '@/app/components/upload-section-file';
|
||||
import { getAllowedFilesExtensions } from '@/app/actions/fileUpload';
|
||||
import { StackedBarChart } from '@/app/components/StackedBarChart';
|
||||
import PageTitleColorFrame from '@/app/ui/page-title-color-frame';
|
||||
import ProtectionStatistic from '@/app/ui/marking-page/new/protection-statistic';
|
||||
|
||||
const data = [
|
||||
{
|
||||
@@ -44,9 +46,13 @@ export default async function Page() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageTitle title="video-protection" />
|
||||
<PageTitleColorFrame
|
||||
title="video-protection"
|
||||
description="multi-layered-protection-for-your-videos"
|
||||
/>
|
||||
<ProtectionStatistic fileType={FILE_TYPE} />
|
||||
<div className="split-blocks">
|
||||
<ProtectionSummary fileType={FILE_TYPE}/>
|
||||
<ProtectionSummary fileType={FILE_TYPE} />
|
||||
<div className="protection-overview">
|
||||
<StackedBarChart data={data} />
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { getUserFilesData, removeUserFile } from '@/app/actions/fileEntity';
|
||||
import ModalWindow from '@/app/components/modalWindow';
|
||||
import { toast } from 'sonner';
|
||||
import { pluralize } from '@/app/lib/pluralize';
|
||||
|
||||
type FileType = 'image' | 'video' | 'audio';
|
||||
|
||||
@@ -603,6 +604,11 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
|
||||
},
|
||||
});
|
||||
|
||||
const pluralizeFiles = (number: number) => {
|
||||
const translate = [t('file'), t('files-few'), t('files')];
|
||||
return pluralize(number, translate[0], translate[1], translate[2]);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="tanstak-table-wrapper">
|
||||
<ModalWindow children={openWindowChildren} state={openWindow} callBack={setOpenWindow}></ModalWindow>
|
||||
@@ -755,7 +761,7 @@ export default function TanstakFilesTable({ fileType }: { fileType: string }) {
|
||||
</strong>
|
||||
</span>
|
||||
<span className="pagination-info-files">
|
||||
| {t('shown')} {table.getRowModel().rows.length} {t('out-of')} {filteredData.length} {t('files')}
|
||||
| {t('shown')} {table.getRowModel().rows.length} {t('out-of')} {filteredData.length} {pluralizeFiles(filteredData.length || 0)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
'use client'
|
||||
|
||||
export const pluralize = (number: number, one: string, few: string, many: string) => {
|
||||
const currentLang = document.documentElement.getAttribute('lang') || 'ru';
|
||||
const getCurrentLang = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
return document?.documentElement?.getAttribute('lang') || 'ru';
|
||||
}
|
||||
return 'ru'; // значение по умолчанию для сервера
|
||||
}
|
||||
const currentLang = getCurrentLang();
|
||||
|
||||
if (currentLang === 'ru') {
|
||||
const n = Math.abs(number) % 100;
|
||||
|
||||
@@ -32,6 +32,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
.page-title-color-frame {
|
||||
background: linear-gradient(135deg, v.$p-color 0%, v.$s-color 100%);
|
||||
padding: 2rem;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 2rem;
|
||||
box-shadow: 0 10px 40px rgba(102, 126, 234, 0.2);
|
||||
|
||||
h1 {
|
||||
color: v.$white;
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 0.5rem 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
p {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.main-containter-wrapper {
|
||||
margin-left: var(--side-bar-width);
|
||||
;
|
||||
@@ -399,4 +423,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.yaPreloadingSuggestBlockContainer {
|
||||
height: 52px !important;
|
||||
}
|
||||
@@ -1825,6 +1825,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
.yaPreloadingSuggestBlockContainer {
|
||||
height: 52px !important;
|
||||
.protection-statistic {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
&-stat-card {
|
||||
background: white;
|
||||
padding: 1.5rem;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.07);
|
||||
border: 2px solid #f3f4f6;
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
&-stat-number {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
/* background: linear-gradient(135deg, #667eea, #764ba2);
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent; */
|
||||
color: v.$p-color;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
&-stat-label {
|
||||
font-size: 0.9rem;
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
'use client'
|
||||
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getUserFilesInfo } from '@/app/actions/action';
|
||||
import { convertBytes } from '@/app/lib/convertBytes';
|
||||
|
||||
type FilesInfo = {
|
||||
totalSize: number;
|
||||
totalCount: number;
|
||||
};
|
||||
|
||||
export default function ProtectionStatistic({ fileType }: { fileType: string }) {
|
||||
const t = useTranslations('Global');
|
||||
|
||||
const getFileTypeFields = (fileType: string): { totalSize: string, totalCount: string } => {
|
||||
switch (fileType) {
|
||||
case 'image':
|
||||
return {
|
||||
totalSize: 'images_size',
|
||||
totalCount: 'images_quantity'
|
||||
};
|
||||
case 'video':
|
||||
return {
|
||||
totalSize: 'videos_size',
|
||||
totalCount: 'videos_quantity'
|
||||
};
|
||||
case 'audio':
|
||||
return {
|
||||
totalSize: 'audios_size',
|
||||
totalCount: 'audios_quantity'
|
||||
};
|
||||
default:
|
||||
return {
|
||||
totalSize: 'all_files_size',
|
||||
totalCount: 'all_files_quantity'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const {
|
||||
data: filesInfo,
|
||||
isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useQuery<{
|
||||
all_files_size: number,
|
||||
all_files_quantity: number
|
||||
}, Error, FilesInfo>({
|
||||
queryKey: ['userFilesInfo'],
|
||||
queryFn: getUserFilesInfo,
|
||||
select: (data): FilesInfo => {
|
||||
if (!data) {
|
||||
return {
|
||||
totalSize: 0,
|
||||
totalCount: 0
|
||||
}
|
||||
}
|
||||
|
||||
const fields = getFileTypeFields(fileType);
|
||||
|
||||
return {
|
||||
totalSize: data[fields.totalSize as keyof typeof data],
|
||||
totalCount: data[fields.totalCount as keyof typeof data]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="protection-statistic">
|
||||
<div className="protection-statistic-stat-card">
|
||||
<div className="protection-statistic-stat-number">0</div>
|
||||
<div className="protection-statistic-stat-label">Видео защищено</div>
|
||||
</div>
|
||||
<div className="protection-statistic-stat-card">
|
||||
<div className="protection-statistic-stat-number">0</div>
|
||||
<div className="protection-statistic-stat-label">Видео проверялось</div>
|
||||
</div>
|
||||
<div className="protection-statistic-stat-card">
|
||||
<div className="protection-statistic-stat-number">
|
||||
{filesInfo?.totalSize ? convertBytes(filesInfo?.totalSize) : 0}
|
||||
</div>
|
||||
<div className="protection-statistic-stat-label">Занимают видео</div>
|
||||
</div>
|
||||
<div className="protection-statistic-stat-card">
|
||||
<div className="protection-statistic-stat-number">0</div>
|
||||
<div className="protection-statistic-stat-label">Найдено нарушений</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function PageTitleColorFrame({ title, description }: { title: string, description: string }) {
|
||||
const t = useTranslations('Global');
|
||||
|
||||
return (
|
||||
<div className="page-title-color-frame">
|
||||
<h1>
|
||||
{t(title)}
|
||||
</h1>
|
||||
<p>
|
||||
{t(description)}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -166,7 +166,10 @@
|
||||
"your-image": "Your images",
|
||||
"your-videos": "Your videos",
|
||||
"your-audios": "Your audios",
|
||||
"your-documents": "Your documents"
|
||||
"your-documents": "Your documents",
|
||||
"multi-layered-protection-for-your-images": "Multi-layered image content protection with invisible watermarks",
|
||||
"multi-layered-protection-for-your-audios": "Multi-layered audio content protection with invisible watermarks",
|
||||
"multi-layered-protection-for-your-videos": "Multi-layered video content protection with invisible watermarks"
|
||||
},
|
||||
"Login-register-form": {
|
||||
"and": "and",
|
||||
|
||||
@@ -166,7 +166,10 @@
|
||||
"your-image": "Ваши изображения",
|
||||
"your-videos": "Ваш видео",
|
||||
"your-audios": "Ваш аудио",
|
||||
"your-documents": "Ваши документы"
|
||||
"your-documents": "Ваши документы",
|
||||
"multi-layered-protection-for-your-images": "Многослойная защита изображений с невидимыми водяными знаками",
|
||||
"multi-layered-protection-for-your-audios": "Многослойная защита аудиоконтента с невидимыми водяными знаками",
|
||||
"multi-layered-protection-for-your-videos": "Многослойная защита видеоконтента с невидимыми водяными знаками"
|
||||
},
|
||||
"Login-register-form": {
|
||||
"and": "и",
|
||||
|
||||
Reference in New Issue
Block a user