diff --git a/src/app/[locale]/pages/violations/[id]/page.tsx b/src/app/[locale]/pages/violations/[id]/page.tsx
new file mode 100644
index 0000000..a1be5f4
--- /dev/null
+++ b/src/app/[locale]/pages/violations/[id]/page.tsx
@@ -0,0 +1,39 @@
+'use client'
+
+import { useParams } from 'next/navigation'
+import ViolationPageTitle from '@/app/ui/violations/file-page/violation-page-title';
+import ViolationPageViolationInfo from '@/app/ui/violations/file-page/violation-page-violation-info';
+import ViolationPpageFileStatistic from '@/app/ui/violations/file-page/violation-page-file-statistic';
+import ViolationPageFileInfo from '@/app/ui/violations/file-page/violation-page-file-info';
+import ViolationPageActions from '@/app/ui/violations/file-page/violation-page-actions';
+import ViolationPageViolationsList from '@/app/ui/violations/file-page/violation-page-violations-list';
+import ViolationPageNote from '@/app/ui/violations/file-page/violation-page-note';
+
+/* violation-details */
+export default function Page() {
+ const params = useParams()
+ const id = params.id
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/styles/pages-styles.scss b/src/app/styles/pages-styles.scss
index bdeaef7..f8e49a5 100644
--- a/src/app/styles/pages-styles.scss
+++ b/src/app/styles/pages-styles.scss
@@ -4137,4 +4137,347 @@
}
}
}
+}
+
+.violation-details {
+ .page-title-color-frame {
+ display: flex;
+ gap: 10px;
+
+ .violation-page-icon {
+ width: 80px;
+ height: 80px;
+ border-radius: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 40px;
+ background: rgba(255, 255, 255, 0.2);
+ backdrop-filter: blur(10px);
+ border: 2px solid rgba(255, 255, 255, 0.3);
+ overflow: hidden;
+
+ .icon {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ .violation-page-info {
+ display: flex;
+ gap: 10px;
+ }
+ }
+
+ .card-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ padding-bottom: 15px;
+ border-bottom: 2px solid #f1f5f9;
+ }
+
+ .info-row {
+ display: flex;
+ justify-content: space-between;
+ padding: 12px 0;
+ border-bottom: 1px solid #f8fafc;
+ }
+
+ .info-label {
+ color: #64748b;
+ font-size: 14px;
+ }
+
+ .info-value {
+ color: #1e293b;
+ font-weight: 600;
+ font-size: 14px;
+ text-align: right;
+ }
+
+ .violation-source {
+ margin-top: 15px;
+
+ &-title {
+ font-size: 14px;
+ color: #64748b;
+ margin-bottom: 8px;
+ font-weight: 600;
+ }
+
+ .url-display {
+ background: #f8fafc;
+ padding: 12px;
+ border-radius: 8px;
+ border: 1px solid #e2e8f0;
+ margin-top: 10px;
+ word-break: break-all;
+
+ .url-link {
+ color: #6366f1;
+ text-decoration: none;
+ font-weight: 600;
+ }
+ }
+ }
+
+ .notes-section {
+ background: #f8fafc;
+ padding: 15px;
+ border-radius: 12px;
+ margin-top: 15px;
+ border: 1px solid #e2e8f0;
+ text-align: left;
+
+ .notes-title {
+ font-size: 14px;
+ font-weight: 600;
+ color: #1e293b;
+ margin-bottom: 10px;
+ text-align: left;
+ }
+
+ .notes-content {
+ font-size: 13px;
+ color: #475569;
+ line-height: 1.6;
+ white-space: pre-line;
+ max-height: 200px;
+ overflow-y: auto;
+ text-align: left;
+ word-wrap: break-word;
+ margin: 0;
+ padding: 0;
+ }
+ }
+
+ .stats-mini-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 15px;
+ margin-bottom: 20px;
+
+ .stat-mini-card {
+ background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
+ padding: 15px;
+ border-radius: 12px;
+ text-align: center;
+ border: 1px solid #e2e8f0;
+ }
+
+ .stat-mini-value {
+ font-size: 28px;
+ font-weight: 700;
+ color: #1e293b;
+ margin-bottom: 5px;
+ }
+
+ .stat-mini-label {
+ font-size: 12px;
+ color: #64748b;
+ }
+ }
+
+ .action-buttons {
+ display: flex;
+ gap: 10px;
+ flex-wrap: wrap;
+
+ .btn-action {
+ flex: 1;
+ min-width: 150px;
+ padding: 12px 20px;
+ border-radius: 12px;
+ font-weight: 600;
+ border: none;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-size: 14px;
+ }
+
+ .btn-warning {
+ background: linear-gradient(135deg, #f59e0b, #d97706);
+ color: white;
+
+ &:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 8px 20px rgba(245, 158, 11, 0.4);
+ }
+ }
+
+ .btn-success {
+ background: linear-gradient(135deg, #10b981, #059669);
+ color: white;
+
+ &:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 8px 20px rgba(16, 185, 129, 0.4);
+ }
+ }
+
+ .btn-secondary {
+ background: linear-gradient(135deg, #64748b, #475569);
+ color: white;
+
+ &:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 8px 20px rgba(100, 116, 139, 0.4);
+ }
+ }
+ }
+
+ .btn-small {
+ padding: 6px 12px;
+ border-radius: 8px;
+ font-size: 12px;
+ font-weight: 600;
+ border: none;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-decoration: none;
+ display: inline-block;
+ }
+
+ .btn-primary-small {
+ background: linear-gradient(135deg, #6366f1, #8b5cf6);
+ color: white;
+
+ &:hover {
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);
+ }
+ }
+
+ .btn-secondary-small {
+ background: #f1f5f9;
+ color: #64748b;
+
+ &:hover {
+ background: #e2e8f0;
+ }
+ }
+
+ .sources-list {
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+
+ .source-card {
+ background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
+ border-radius: 12px;
+ padding: 15px;
+ border: 1px solid #e2e8f0;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
+ border-color: #cbd5e1;
+ }
+ }
+
+ .source-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ }
+
+ .source-url {
+ color: #6366f1;
+ font-weight: 600;
+ font-size: 14px;
+ text-decoration: none;
+ word-break: break-all;
+ flex: 1;
+ }
+
+ .source-status {
+ padding: 4px 10px;
+ border-radius: 6px;
+ font-size: 11px;
+ font-weight: 600;
+ white-space: nowrap;
+ margin-left: 10px;
+
+ &.new {
+ background: #fef2f2;
+ color: #dc2626;
+ }
+ }
+
+ .source-meta {
+ display: flex;
+ gap: 15px;
+ font-size: 12px;
+ color: #64748b;
+ margin-bottom: 10px;
+ flex-wrap: wrap;
+ }
+
+ .source-actions {
+ display: flex;
+ gap: 10px;
+ flex-wrap: wrap;
+ margin-top: 10px;
+ }
+ }
+
+ .pagination {
+ margin-top: 20px;
+ display: flex;
+ justify-content: center;
+ gap: 4px;
+
+ &__item {
+ padding: 8px 12px;
+ border-radius: 8px;
+ text-decoration: none;
+ font-weight: 600;
+ background: white;
+ color: #374151;
+ border: 2px solid #e5e7eb;
+ transition: all 0.2s ease;
+
+ &:hover {
+ border-color: #667eea;
+ }
+
+ &--active {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ color: white;
+ border: 2px solid #667eea;
+
+ &:hover {
+ border-color: #667eea;
+ }
+ }
+ }
+ }
+
+ .note-form {
+ margin-top: 0;
+ border: none;
+ padding: 0;
+ background: #f8fafc;
+ }
+
+ .note-textarea {
+ width: 100%;
+ min-height: 80px;
+ padding: 12px;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ font-size: 14px;
+ font-family: inherit;
+ resize: vertical;
+ box-sizing: border-box;
+
+ &:focus {
+ outline: none;
+ border-color: #6366f1;
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/app/ui/icons/icons.tsx b/src/app/ui/icons/icons.tsx
index 6e2f52c..b8a8d65 100644
--- a/src/app/ui/icons/icons.tsx
+++ b/src/app/ui/icons/icons.tsx
@@ -64,6 +64,16 @@ export function IconEye() {
)
}
+export function IconEyeDashed() {
+ return (
+
+ )
+}
+
export function IconDoubleArrowRight() {
return (
@@ -186,6 +196,6 @@ export function IconWarning() {
export function IconGraph() {
return (
-
+
)
}
\ No newline at end of file
diff --git a/src/app/ui/violations/file-page/violation-page-actions.tsx b/src/app/ui/violations/file-page/violation-page-actions.tsx
new file mode 100644
index 0000000..f4962f0
--- /dev/null
+++ b/src/app/ui/violations/file-page/violation-page-actions.tsx
@@ -0,0 +1,33 @@
+export default function ViolationPageActions() {
+ return (
+
+
+
+ Действия
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/ui/violations/file-page/violation-page-file-info.tsx b/src/app/ui/violations/file-page/violation-page-file-info.tsx
new file mode 100644
index 0000000..f67f2ea
--- /dev/null
+++ b/src/app/ui/violations/file-page/violation-page-file-info.tsx
@@ -0,0 +1,40 @@
+export default function ViolationPageFileInfo() {
+ return (
+
+
+
+
+ 📄 Информация о файле
+
+
+
+
+ Тип файла
+ fileType
+
+
+ Размер
+ 0 КБ
+
+
+ Загружен
+ 0
+
+
+ Водяной знак
+
+ Применен
+
+
+
+ Уровень защиты
+
+ Максимальный
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/ui/violations/file-page/violation-page-file-statistic.tsx b/src/app/ui/violations/file-page/violation-page-file-statistic.tsx
new file mode 100644
index 0000000..e28de7b
--- /dev/null
+++ b/src/app/ui/violations/file-page/violation-page-file-statistic.tsx
@@ -0,0 +1,52 @@
+export default function ViolationPpageFileStatistic() {
+ return (
+
+
+
+ Статистика по файлу
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/ui/violations/file-page/violation-page-note.tsx b/src/app/ui/violations/file-page/violation-page-note.tsx
new file mode 100644
index 0000000..4c721c6
--- /dev/null
+++ b/src/app/ui/violations/file-page/violation-page-note.tsx
@@ -0,0 +1,24 @@
+export default function ViolationPageNote() {
+ return (
+
+
+
+
+ ✏️ Добавить заметку
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/ui/violations/file-page/violation-page-title.tsx b/src/app/ui/violations/file-page/violation-page-title.tsx
new file mode 100644
index 0000000..0c1bcf5
--- /dev/null
+++ b/src/app/ui/violations/file-page/violation-page-title.tsx
@@ -0,0 +1,43 @@
+import { useTranslations } from 'next-intl';
+import { useParams } from 'next/navigation'
+import { IconEyeDashed } from '@/app/ui/icons/icons';
+
+export default function ViolationPageTitle() {
+ const t = useTranslations('Global');
+ const params = useParams()
+ const id = params.id
+
+ return (
+
+
+
+
+
+
+ file id: {id}
+
+
+
+ fileType
+
+
+
+ fileSize
+
+
+
+ fileViolationDate
+
+
+
+ fileViolationType
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/ui/violations/file-page/violation-page-violation-info.tsx b/src/app/ui/violations/file-page/violation-page-violation-info.tsx
new file mode 100644
index 0000000..6226146
--- /dev/null
+++ b/src/app/ui/violations/file-page/violation-page-violation-info.tsx
@@ -0,0 +1,50 @@
+export default function ViolationPageViolationInfo() {
+ return (
+
+
+
+ Информация о нарушении
+
+
+
+
+ Тип нарушения
+ Неавторизованное использование
+
+
+
+ Дата обнаружения
+ 28.02.2026 07:48
+
+
+
+ Уверенность
+ 85%
+
+
+
+
+ Источник нарушения:
+
+
+
+
+
+
📝 Заметки:
+
+ Заметок пока нет. Вы можете добавить первую заметку ниже.
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/ui/violations/file-page/violation-page-violations-list.tsx b/src/app/ui/violations/file-page/violation-page-violations-list.tsx
new file mode 100644
index 0000000..1dd2ec4
--- /dev/null
+++ b/src/app/ui/violations/file-page/violation-page-violations-list.tsx
@@ -0,0 +1,52 @@
+export default function ViolationPageViolationsList() {
+ return (
+
+
+
+ Все нарушения этого файла
+
+
+ Всего: 0 | Страница 0 из 0
+
+
+
+ {/* это нужно будет сделать отдельным компонентом */}
+
+
+
+
+ 28.02.2026 07:48
+ Неавторизованное использование
+ 85%
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file