Initial version
This commit is contained in:
57
CLAUDE.md
Normal file
57
CLAUDE.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
This is a website project for the radiophotonics department (ru.radiophotonics), currently in planning phase. The project is designed to create a flexible, easily administrable website for academic/research purposes.
|
||||||
|
|
||||||
|
## Planned Architecture
|
||||||
|
|
||||||
|
Based on Plan.md, this will be a full-stack web application with:
|
||||||
|
|
||||||
|
- **Frontend**: React + Next.js
|
||||||
|
- **Backend**: Go (REST API)
|
||||||
|
- **Database**: PostgreSQL
|
||||||
|
- **File Storage**: MinIO or S3-compatible storage
|
||||||
|
- **Authentication**: JWT with role-based access (Editor with login, Observer without login)
|
||||||
|
- **Admin Panel**: Web interface for content management
|
||||||
|
|
||||||
|
## Main Sections (Planned)
|
||||||
|
|
||||||
|
1. **Main Page** - General lab information and mission
|
||||||
|
2. **Publications and News** - Publication lists, PDF attachments, news publishing
|
||||||
|
3. **RIDs (Intellectual Property Results)** - Patents, developments, programs catalog
|
||||||
|
4. **Projects** - Project listings with related RIDs, publications, news, partners
|
||||||
|
5. **Partners** - Collaboration information and project links
|
||||||
|
6. **Staff** - Employee directory with photos, positions, contacts, publications
|
||||||
|
7. **Contacts** - Address, maps (Google/Yandex), contact form
|
||||||
|
8. **For Students** - Educational materials, handbooks (PDFs), schedules, instructions
|
||||||
|
|
||||||
|
## Technical Stack (Recommended)
|
||||||
|
|
||||||
|
### Backend (Go)
|
||||||
|
- Gin or Echo for API framework
|
||||||
|
- GORM for database ORM
|
||||||
|
- JWT for authentication
|
||||||
|
|
||||||
|
### Frontend (Next.js)
|
||||||
|
- TailwindCSS or shadcn/ui for styling
|
||||||
|
- Axios/React Query for API communication
|
||||||
|
|
||||||
|
### Editor Features
|
||||||
|
- WYSIWYG editor (tiptap or CKEditor)
|
||||||
|
- Drag-and-drop file upload
|
||||||
|
- Content management panel
|
||||||
|
|
||||||
|
## Development Phases
|
||||||
|
|
||||||
|
1. **Design Phase**: Database schema, API design
|
||||||
|
2. **MVP**: Basic backend CRUD + frontend with main sections + auth
|
||||||
|
3. **Admin Panel**: Content editing interface, file uploads
|
||||||
|
4. **UI Improvements**: Search, filters, image optimization, user roles
|
||||||
|
5. **Deployment**: Docker deployment, SSL setup
|
||||||
|
|
||||||
|
## Repository Status
|
||||||
|
|
||||||
|
This repository is in the initial planning stage with only Plan.md containing the project specification. No build tools, package managers, or source code have been implemented yet.
|
||||||
41
frontend/.gitignore
vendored
Normal file
41
frontend/.gitignore
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# env files (can opt-in for committing if needed)
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
36
frontend/README.md
Normal file
36
frontend/README.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
First, run the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# or
|
||||||
|
yarn dev
|
||||||
|
# or
|
||||||
|
pnpm dev
|
||||||
|
# or
|
||||||
|
bun dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
|
|
||||||
|
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||||
|
|
||||||
|
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
To learn more about Next.js, take a look at the following resources:
|
||||||
|
|
||||||
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
|
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||||
|
|
||||||
|
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||||
|
|
||||||
|
## Deploy on Vercel
|
||||||
|
|
||||||
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||||
25
frontend/eslint.config.mjs
Normal file
25
frontend/eslint.config.mjs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { dirname } from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
import { FlatCompat } from "@eslint/eslintrc";
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
const compat = new FlatCompat({
|
||||||
|
baseDirectory: __dirname,
|
||||||
|
});
|
||||||
|
|
||||||
|
const eslintConfig = [
|
||||||
|
...compat.extends("next/core-web-vitals", "next/typescript"),
|
||||||
|
{
|
||||||
|
ignores: [
|
||||||
|
"node_modules/**",
|
||||||
|
".next/**",
|
||||||
|
"out/**",
|
||||||
|
"build/**",
|
||||||
|
"next-env.d.ts",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default eslintConfig;
|
||||||
7
frontend/next.config.ts
Normal file
7
frontend/next.config.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
|
const nextConfig: NextConfig = {
|
||||||
|
/* config options here */
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
6090
frontend/package-lock.json
generated
Normal file
6090
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
frontend/package.json
Normal file
27
frontend/package.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "frontend",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev --turbopack",
|
||||||
|
"build": "next build --turbopack",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "eslint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "19.1.0",
|
||||||
|
"react-dom": "19.1.0",
|
||||||
|
"next": "15.5.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/react": "^19",
|
||||||
|
"@types/react-dom": "^19",
|
||||||
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"tailwindcss": "^4",
|
||||||
|
"eslint": "^9",
|
||||||
|
"eslint-config-next": "15.5.3",
|
||||||
|
"@eslint/eslintrc": "^3"
|
||||||
|
}
|
||||||
|
}
|
||||||
5
frontend/postcss.config.mjs
Normal file
5
frontend/postcss.config.mjs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const config = {
|
||||||
|
plugins: ["@tailwindcss/postcss"],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
1
frontend/public/file.svg
Normal file
1
frontend/public/file.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 391 B |
1
frontend/public/globe.svg
Normal file
1
frontend/public/globe.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
1
frontend/public/next.svg
Normal file
1
frontend/public/next.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
1
frontend/public/vercel.svg
Normal file
1
frontend/public/vercel.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||||
|
After Width: | Height: | Size: 128 B |
1
frontend/public/window.svg
Normal file
1
frontend/public/window.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||||
|
After Width: | Height: | Size: 385 B |
226
frontend/src/app/contacts/page.tsx
Normal file
226
frontend/src/app/contacts/page.tsx
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
export default function ContactsPage() {
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
name: '',
|
||||||
|
email: '',
|
||||||
|
subject: '',
|
||||||
|
message: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
// В реальном приложении здесь была бы отправка формы
|
||||||
|
alert('Сообщение отправлено! (это демо-версия)');
|
||||||
|
setFormData({ name: '', email: '', subject: '', message: '' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
|
||||||
|
setFormData({
|
||||||
|
...formData,
|
||||||
|
[e.target.name]: e.target.value
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
|
<div className="mb-8">
|
||||||
|
<h1 className="text-4xl font-bold text-gray-900 mb-4">Контакты</h1>
|
||||||
|
<p className="text-lg text-gray-600">
|
||||||
|
Свяжитесь с нами для получения дополнительной информации о наших исследованиях и возможностях сотрудничества
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid lg:grid-cols-2 gap-12">
|
||||||
|
{/* Contact Information */}
|
||||||
|
<div>
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-6">Контактная информация</h2>
|
||||||
|
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold text-gray-900 mb-3">Адрес</h3>
|
||||||
|
<div className="flex items-start space-x-3">
|
||||||
|
<span className="text-blue-600 mt-1">📍</span>
|
||||||
|
<div>
|
||||||
|
<p className="text-gray-700">119991, Москва</p>
|
||||||
|
<p className="text-gray-700">ул. Научная, д. 1</p>
|
||||||
|
<p className="text-gray-700">Отдел радиофотоники</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold text-gray-900 mb-3">Телефон</h3>
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
|
<span className="text-blue-600">📞</span>
|
||||||
|
<a href="tel:+74951234567" className="text-gray-700 hover:text-blue-600 transition-colors">
|
||||||
|
+7 (495) 123-45-67
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold text-gray-900 mb-3">Email</h3>
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
|
<span className="text-blue-600">📧</span>
|
||||||
|
<a href="mailto:info@radiophotonics.ru" className="text-gray-700 hover:text-blue-600 transition-colors">
|
||||||
|
info@radiophotonics.ru
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold text-gray-900 mb-3">Время работы</h3>
|
||||||
|
<div className="flex items-start space-x-3">
|
||||||
|
<span className="text-blue-600 mt-1">🕐</span>
|
||||||
|
<div>
|
||||||
|
<p className="text-gray-700">Понедельник - Пятница: 9:00 - 18:00</p>
|
||||||
|
<p className="text-gray-700">Суббота - Воскресенье: выходной</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Map placeholder */}
|
||||||
|
<div className="mt-8">
|
||||||
|
<h3 className="text-lg font-semibold text-gray-900 mb-3">Местоположение</h3>
|
||||||
|
<div className="bg-gray-200 rounded-lg h-64 flex items-center justify-center">
|
||||||
|
<div className="text-center">
|
||||||
|
<span className="text-4xl text-gray-400 mb-2 block">🗺️</span>
|
||||||
|
<p className="text-gray-600">Интерактивная карта</p>
|
||||||
|
<p className="text-sm text-gray-500">(будет добавлена позже)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Contact Form */}
|
||||||
|
<div>
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-6">Обратная связь</h2>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-6">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="name" className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Имя *
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="name"
|
||||||
|
name="name"
|
||||||
|
required
|
||||||
|
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
|
value={formData.name}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Email *
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
id="email"
|
||||||
|
name="email"
|
||||||
|
required
|
||||||
|
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
|
value={formData.email}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label htmlFor="subject" className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Тема обращения *
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="subject"
|
||||||
|
name="subject"
|
||||||
|
required
|
||||||
|
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
|
value={formData.subject}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
<option value="">Выберите тему</option>
|
||||||
|
<option value="collaboration">Сотрудничество</option>
|
||||||
|
<option value="research">Исследования</option>
|
||||||
|
<option value="publications">Публикации</option>
|
||||||
|
<option value="education">Образование</option>
|
||||||
|
<option value="other">Другое</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label htmlFor="message" className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Сообщение *
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="message"
|
||||||
|
name="message"
|
||||||
|
required
|
||||||
|
rows={6}
|
||||||
|
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-vertical"
|
||||||
|
value={formData.message}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="Опишите ваш вопрос или предложение..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="w-full bg-blue-600 text-white px-6 py-3 rounded-md hover:bg-blue-700 transition-colors font-medium"
|
||||||
|
>
|
||||||
|
Отправить сообщение
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div className="mt-6 p-4 bg-blue-50 rounded-lg">
|
||||||
|
<p className="text-sm text-blue-800">
|
||||||
|
<strong>Примечание:</strong> Мы отвечаем на все обращения в течение 1-2 рабочих дней.
|
||||||
|
Для срочных вопросов используйте телефон.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Additional Information */}
|
||||||
|
<div className="mt-16 bg-gray-50 rounded-lg p-8">
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-6 text-center">Направления сотрудничества</h2>
|
||||||
|
|
||||||
|
<div className="grid md:grid-cols-3 gap-6">
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
|
<span className="text-2xl">🔬</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-semibold mb-2">Научные исследования</h3>
|
||||||
|
<p className="text-gray-600 text-sm">
|
||||||
|
Совместные исследования в области радиофотоники и оптических технологий
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
|
<span className="text-2xl">🤝</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-semibold mb-2">Промышленное партнерство</h3>
|
||||||
|
<p className="text-gray-600 text-sm">
|
||||||
|
Внедрение разработок и технологий в промышленные решения
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
|
<span className="text-2xl">🎓</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-semibold mb-2">Образование</h3>
|
||||||
|
<p className="text-gray-600 text-sm">
|
||||||
|
Образовательные программы, стажировки и подготовка кадров
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
BIN
frontend/src/app/favicon.ico
Normal file
BIN
frontend/src/app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
26
frontend/src/app/globals.css
Normal file
26
frontend/src/app/globals.css
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background: #ffffff;
|
||||||
|
--foreground: #171717;
|
||||||
|
}
|
||||||
|
|
||||||
|
@theme inline {
|
||||||
|
--color-background: var(--background);
|
||||||
|
--color-foreground: var(--foreground);
|
||||||
|
--font-sans: var(--font-geist-sans);
|
||||||
|
--font-mono: var(--font-geist-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--background: #0a0a0a;
|
||||||
|
--foreground: #ededed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--background);
|
||||||
|
color: var(--foreground);
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
32
frontend/src/app/layout.tsx
Normal file
32
frontend/src/app/layout.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { Inter } from "next/font/google";
|
||||||
|
import "./globals.css";
|
||||||
|
import Header from "@/components/Header";
|
||||||
|
import Footer from "@/components/Footer";
|
||||||
|
|
||||||
|
const inter = Inter({
|
||||||
|
subsets: ["latin", "cyrillic"],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Отдел Радиофотоники",
|
||||||
|
description: "Научно-исследовательский центр в области радиофотоники и оптических технологий",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: Readonly<{
|
||||||
|
children: React.ReactNode;
|
||||||
|
}>) {
|
||||||
|
return (
|
||||||
|
<html lang="ru">
|
||||||
|
<body className={`${inter.className} antialiased min-h-screen flex flex-col`}>
|
||||||
|
<Header />
|
||||||
|
<main className="flex-1">
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
148
frontend/src/app/page.tsx
Normal file
148
frontend/src/app/page.tsx
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import Link from 'next/link';
|
||||||
|
import { mockNews, mockPublications, mockProjects } from '@/lib/mockData';
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
const latestNews = mockNews.slice(0, 2);
|
||||||
|
const recentPublications = mockPublications.slice(0, 3);
|
||||||
|
const activeProjects = mockProjects.filter(p => p.status === 'active').slice(0, 2);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
|
{/* Hero Section */}
|
||||||
|
<section className="text-center py-16 bg-gradient-to-r from-blue-50 to-indigo-50 rounded-lg mb-12">
|
||||||
|
<h1 className="text-4xl md:text-6xl font-bold text-gray-900 mb-6">
|
||||||
|
Отдел Радиофотоники
|
||||||
|
</h1>
|
||||||
|
<p className="text-xl text-gray-600 max-w-3xl mx-auto mb-8">
|
||||||
|
Ведущий научно-исследовательский центр в области радиофотоники и оптических технологий.
|
||||||
|
Мы занимаемся разработкой передовых решений для телекоммуникаций, сенсорики и обработки сигналов.
|
||||||
|
</p>
|
||||||
|
<div className="space-x-4">
|
||||||
|
<Link
|
||||||
|
href="/publications"
|
||||||
|
className="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700 transition-colors inline-block"
|
||||||
|
>
|
||||||
|
Наши публикации
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="/projects"
|
||||||
|
className="bg-white text-blue-600 border border-blue-600 px-6 py-3 rounded-lg hover:bg-blue-50 transition-colors inline-block"
|
||||||
|
>
|
||||||
|
Проекты
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Latest News */}
|
||||||
|
<section className="mb-12">
|
||||||
|
<div className="flex justify-between items-center mb-6">
|
||||||
|
<h2 className="text-3xl font-bold text-gray-900">Последние новости</h2>
|
||||||
|
<Link href="/news" className="text-blue-600 hover:text-blue-800">
|
||||||
|
Все новости →
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="grid md:grid-cols-2 gap-6">
|
||||||
|
{latestNews.map(news => (
|
||||||
|
<div key={news.id} className="bg-white border rounded-lg p-6 shadow-sm hover:shadow-md transition-shadow">
|
||||||
|
<h3 className="text-xl font-semibold mb-3 text-gray-900">{news.title}</h3>
|
||||||
|
<p className="text-gray-600 mb-4 line-clamp-3">{news.content}</p>
|
||||||
|
<div className="flex justify-between items-center text-sm text-gray-500">
|
||||||
|
<span>{news.author}</span>
|
||||||
|
<span>{new Date(news.date).toLocaleDateString('ru-RU')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Recent Publications */}
|
||||||
|
<section className="mb-12">
|
||||||
|
<div className="flex justify-between items-center mb-6">
|
||||||
|
<h2 className="text-3xl font-bold text-gray-900">Последние публикации</h2>
|
||||||
|
<Link href="/publications" className="text-blue-600 hover:text-blue-800">
|
||||||
|
Все публикации →
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="grid gap-4">
|
||||||
|
{recentPublications.map(pub => (
|
||||||
|
<div key={pub.id} className="bg-white border rounded-lg p-6 shadow-sm hover:shadow-md transition-shadow">
|
||||||
|
<h3 className="text-lg font-semibold mb-2 text-gray-900">{pub.title}</h3>
|
||||||
|
<p className="text-gray-600 mb-2">
|
||||||
|
{pub.authors.join(', ')} • {pub.journal} • {pub.year}
|
||||||
|
</p>
|
||||||
|
<p className="text-gray-700 line-clamp-2">{pub.abstract}</p>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-3">
|
||||||
|
{pub.tags.map(tag => (
|
||||||
|
<span key={tag} className="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded">
|
||||||
|
{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Active Projects */}
|
||||||
|
<section className="mb-12">
|
||||||
|
<div className="flex justify-between items-center mb-6">
|
||||||
|
<h2 className="text-3xl font-bold text-gray-900">Активные проекты</h2>
|
||||||
|
<Link href="/projects" className="text-blue-600 hover:text-blue-800">
|
||||||
|
Все проекты →
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="grid md:grid-cols-2 gap-6">
|
||||||
|
{activeProjects.map(project => (
|
||||||
|
<div key={project.id} className="bg-white border rounded-lg p-6 shadow-sm hover:shadow-md transition-shadow">
|
||||||
|
<div className="flex items-center justify-between mb-3">
|
||||||
|
<h3 className="text-xl font-semibold text-gray-900">{project.title}</h3>
|
||||||
|
<span className="bg-green-100 text-green-800 text-xs px-2 py-1 rounded">
|
||||||
|
Активный
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-gray-700 mb-4 line-clamp-3">{project.description}</p>
|
||||||
|
<div className="text-sm text-gray-500">
|
||||||
|
<p>Период: {new Date(project.startDate).getFullYear()} - {project.endDate ? new Date(project.endDate).getFullYear() : 'н.в.'}</p>
|
||||||
|
{project.funding && <p>Финансирование: {project.funding}</p>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Research Areas */}
|
||||||
|
<section className="bg-gray-50 rounded-lg p-8">
|
||||||
|
<h2 className="text-3xl font-bold text-gray-900 mb-8 text-center">Направления исследований</h2>
|
||||||
|
<div className="grid md:grid-cols-3 gap-6">
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
|
<span className="text-2xl">🔬</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl font-semibold mb-3">Радиофотоника</h3>
|
||||||
|
<p className="text-gray-600">
|
||||||
|
Исследования в области взаимодействия оптических и микроволновых сигналов
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
|
<span className="text-2xl">📡</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl font-semibold mb-3">Оптические телекоммуникации</h3>
|
||||||
|
<p className="text-gray-600">
|
||||||
|
Разработка систем высокоскоростной передачи данных по оптическим каналам
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
|
<span className="text-2xl">⚛️</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl font-semibold mb-3">Квантовые технологии</h3>
|
||||||
|
<p className="text-gray-600">
|
||||||
|
Исследование квантовых эффектов в оптических системах и квантовых коммуникаций
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
140
frontend/src/app/projects/page.tsx
Normal file
140
frontend/src/app/projects/page.tsx
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
import { mockProjects, mockStaff, mockPublications } from '@/lib/mockData';
|
||||||
|
import { Project } from '@/types';
|
||||||
|
|
||||||
|
export default function ProjectsPage() {
|
||||||
|
const activeProjects = mockProjects.filter(p => p.status === 'active');
|
||||||
|
const completedProjects = mockProjects.filter(p => p.status === 'completed');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
|
<div className="mb-8">
|
||||||
|
<h1 className="text-4xl font-bold text-gray-900 mb-4">Проекты</h1>
|
||||||
|
<p className="text-lg text-gray-600">
|
||||||
|
Исследовательские проекты и разработки отдела радиофотоники
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Active Projects */}
|
||||||
|
{activeProjects.length > 0 && (
|
||||||
|
<section className="mb-12">
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-6">Активные проекты</h2>
|
||||||
|
<div className="grid gap-6">
|
||||||
|
{activeProjects.map(project => (
|
||||||
|
<ProjectCard key={project.id} project={project} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Completed Projects */}
|
||||||
|
{completedProjects.length > 0 && (
|
||||||
|
<section>
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 mb-6">Завершенные проекты</h2>
|
||||||
|
<div className="grid gap-6">
|
||||||
|
{completedProjects.map(project => (
|
||||||
|
<ProjectCard key={project.id} project={project} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ProjectCard({ project }: { project: Project }) {
|
||||||
|
const teamMembers = mockStaff.filter(staff => project.team.includes(staff.id));
|
||||||
|
const projectPublications = mockPublications.filter(pub =>
|
||||||
|
project.publications.includes(pub.id)
|
||||||
|
);
|
||||||
|
|
||||||
|
const statusColors = {
|
||||||
|
active: 'bg-green-100 text-green-800',
|
||||||
|
completed: 'bg-blue-100 text-blue-800',
|
||||||
|
planned: 'bg-yellow-100 text-yellow-800'
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusLabels = {
|
||||||
|
active: 'Активный',
|
||||||
|
completed: 'Завершен',
|
||||||
|
planned: 'Планируется'
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white border rounded-lg p-6 shadow-sm hover:shadow-md transition-shadow">
|
||||||
|
<div className="flex items-start justify-between mb-4">
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-3 mb-2">
|
||||||
|
<h3 className="text-2xl font-semibold text-gray-900">{project.title}</h3>
|
||||||
|
<span className={`text-xs px-2 py-1 rounded ${statusColors[project.status]}`}>
|
||||||
|
{statusLabels[project.status]}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-sm text-gray-600 mb-4">
|
||||||
|
<span className="font-medium">Период:</span> {new Date(project.startDate).getFullYear()} - {project.endDate ? new Date(project.endDate).getFullYear() : 'н.в.'}
|
||||||
|
{project.funding && (
|
||||||
|
<span className="ml-4">
|
||||||
|
<span className="font-medium">Финансирование:</span> {project.funding}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-6">
|
||||||
|
<p className="text-gray-700 leading-relaxed">{project.description}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Team */}
|
||||||
|
{teamMembers.length > 0 && (
|
||||||
|
<div className="mb-4">
|
||||||
|
<h4 className="text-sm font-semibold text-gray-900 mb-2">Команда проекта:</h4>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{teamMembers.map(member => (
|
||||||
|
<div key={member.id} className="bg-gray-100 rounded-lg px-3 py-1">
|
||||||
|
<p className="text-sm font-medium text-gray-900">{member.name}</p>
|
||||||
|
<p className="text-xs text-gray-600">{member.position}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Partners */}
|
||||||
|
{project.partners && project.partners.length > 0 && (
|
||||||
|
<div className="mb-4">
|
||||||
|
<h4 className="text-sm font-semibold text-gray-900 mb-2">Партнеры:</h4>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{project.partners.map(partner => (
|
||||||
|
<span
|
||||||
|
key={partner}
|
||||||
|
className="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded"
|
||||||
|
>
|
||||||
|
{partner}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Publications */}
|
||||||
|
{projectPublications.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<h4 className="text-sm font-semibold text-gray-900 mb-2">
|
||||||
|
Публикации проекта ({projectPublications.length}):
|
||||||
|
</h4>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{projectPublications.map(pub => (
|
||||||
|
<div key={pub.id} className="border-l-4 border-blue-200 pl-3">
|
||||||
|
<p className="text-sm font-medium text-gray-900">{pub.title}</p>
|
||||||
|
<p className="text-xs text-gray-600">
|
||||||
|
{pub.authors.join(', ')} • {pub.journal} • {pub.year}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
202
frontend/src/app/publications/page.tsx
Normal file
202
frontend/src/app/publications/page.tsx
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { mockPublications } from '@/lib/mockData';
|
||||||
|
import { Publication } from '@/types';
|
||||||
|
|
||||||
|
export default function PublicationsPage() {
|
||||||
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
|
const [selectedType, setSelectedType] = useState<string>('all');
|
||||||
|
const [selectedYear, setSelectedYear] = useState<string>('all');
|
||||||
|
|
||||||
|
const filteredPublications = mockPublications.filter(publication => {
|
||||||
|
const matchesSearch =
|
||||||
|
publication.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
|
publication.authors.some(author => author.toLowerCase().includes(searchTerm.toLowerCase())) ||
|
||||||
|
publication.journal.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
|
publication.tags.some(tag => tag.toLowerCase().includes(searchTerm.toLowerCase()));
|
||||||
|
|
||||||
|
const matchesType = selectedType === 'all' || publication.type === selectedType;
|
||||||
|
const matchesYear = selectedYear === 'all' || publication.year.toString() === selectedYear;
|
||||||
|
|
||||||
|
return matchesSearch && matchesType && matchesYear;
|
||||||
|
});
|
||||||
|
|
||||||
|
const uniqueYears = Array.from(new Set(mockPublications.map(p => p.year))).sort((a, b) => b - a);
|
||||||
|
const uniqueTypes = Array.from(new Set(mockPublications.map(p => p.type)));
|
||||||
|
|
||||||
|
const typeLabels: Record<string, string> = {
|
||||||
|
'article': 'Статья',
|
||||||
|
'conference': 'Конференция',
|
||||||
|
'book': 'Книга',
|
||||||
|
'patent': 'Патент'
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
|
<div className="mb-8">
|
||||||
|
<h1 className="text-4xl font-bold text-gray-900 mb-4">Публикации</h1>
|
||||||
|
<p className="text-lg text-gray-600">
|
||||||
|
Научные работы и публикации сотрудников отдела радиофотоники
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Search and Filters */}
|
||||||
|
<div className="bg-white border rounded-lg p-6 mb-8 shadow-sm">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label htmlFor="search" className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Поиск
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="search"
|
||||||
|
placeholder="Поиск по названию, авторам, журналу или тегам..."
|
||||||
|
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label htmlFor="type" className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Тип публикации
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="type"
|
||||||
|
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
|
value={selectedType}
|
||||||
|
onChange={(e) => setSelectedType(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="all">Все типы</option>
|
||||||
|
{uniqueTypes.map(type => (
|
||||||
|
<option key={type} value={type}>{typeLabels[type] || type}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label htmlFor="year" className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Год
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="year"
|
||||||
|
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
|
value={selectedYear}
|
||||||
|
onChange={(e) => setSelectedYear(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="all">Все годы</option>
|
||||||
|
{uniqueYears.map(year => (
|
||||||
|
<option key={year} value={year.toString()}>{year}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 flex items-center justify-between">
|
||||||
|
<p className="text-sm text-gray-600">
|
||||||
|
Найдено публикаций: {filteredPublications.length} из {mockPublications.length}
|
||||||
|
</p>
|
||||||
|
{(searchTerm || selectedType !== 'all' || selectedYear !== 'all') && (
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
setSearchTerm('');
|
||||||
|
setSelectedType('all');
|
||||||
|
setSelectedYear('all');
|
||||||
|
}}
|
||||||
|
className="text-sm text-blue-600 hover:text-blue-800"
|
||||||
|
>
|
||||||
|
Сбросить фильтры
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Publications List */}
|
||||||
|
<div className="space-y-6">
|
||||||
|
{filteredPublications.length === 0 ? (
|
||||||
|
<div className="text-center py-12">
|
||||||
|
<p className="text-gray-500 text-lg">Публикации не найдены</p>
|
||||||
|
<p className="text-gray-400 text-sm mt-2">Попробуйте изменить параметры поиска</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
filteredPublications.map(publication => (
|
||||||
|
<PublicationCard key={publication.id} publication={publication} />
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function PublicationCard({ publication }: { publication: Publication }) {
|
||||||
|
const typeLabels: Record<string, string> = {
|
||||||
|
'article': 'Статья',
|
||||||
|
'conference': 'Конференция',
|
||||||
|
'book': 'Книга',
|
||||||
|
'patent': 'Патент'
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white border rounded-lg p-6 shadow-sm hover:shadow-md transition-shadow">
|
||||||
|
<div className="flex items-start justify-between mb-4">
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-3 mb-2">
|
||||||
|
<h2 className="text-xl font-semibold text-gray-900">{publication.title}</h2>
|
||||||
|
<span className="bg-gray-100 text-gray-700 text-xs px-2 py-1 rounded">
|
||||||
|
{typeLabels[publication.type] || publication.type}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-gray-600 mb-2">
|
||||||
|
<span className="font-medium">Авторы:</span> {publication.authors.join(', ')}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p className="text-gray-600 mb-2">
|
||||||
|
<span className="font-medium">Журнал:</span> {publication.journal} • {publication.year}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{publication.doi && (
|
||||||
|
<p className="text-gray-600 mb-2">
|
||||||
|
<span className="font-medium">DOI:</span>
|
||||||
|
<a href={`https://doi.org/${publication.doi}`} target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:text-blue-800 ml-1">
|
||||||
|
{publication.doi}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{publication.pdfUrl && (
|
||||||
|
<div className="ml-4">
|
||||||
|
<a
|
||||||
|
href={publication.pdfUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition-colors text-sm"
|
||||||
|
>
|
||||||
|
PDF
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4">
|
||||||
|
<p className="text-gray-700 leading-relaxed">{publication.abstract}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{publication.tags.map(tag => (
|
||||||
|
<span
|
||||||
|
key={tag}
|
||||||
|
className="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded hover:bg-blue-200 cursor-pointer transition-colors"
|
||||||
|
onClick={() => {
|
||||||
|
// В будущем можно добавить фильтрацию по тегам
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
110
frontend/src/app/staff/page.tsx
Normal file
110
frontend/src/app/staff/page.tsx
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import { mockStaff, mockPublications } from '@/lib/mockData';
|
||||||
|
import { Staff } from '@/types';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
export default function StaffPage() {
|
||||||
|
return (
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
|
<div className="mb-8">
|
||||||
|
<h1 className="text-4xl font-bold text-gray-900 mb-4">Сотрудники</h1>
|
||||||
|
<p className="text-lg text-gray-600">
|
||||||
|
Наша команда опытных исследователей и специалистов в области радиофотоники
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
|
{mockStaff.map(staff => (
|
||||||
|
<StaffCard key={staff.id} staff={staff} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function StaffCard({ staff }: { staff: Staff }) {
|
||||||
|
const staffPublications = mockPublications.filter(pub =>
|
||||||
|
staff.publications.includes(pub.id)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white border rounded-lg overflow-hidden shadow-sm hover:shadow-md transition-shadow">
|
||||||
|
{/* Photo */}
|
||||||
|
<div className="relative h-64 bg-gray-200">
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-gray-900/20 to-transparent" />
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center">
|
||||||
|
<div className="w-32 h-32 bg-gray-300 rounded-full flex items-center justify-center">
|
||||||
|
<span className="text-3xl text-gray-600">👤</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<div className="p-6">
|
||||||
|
<div className="mb-4">
|
||||||
|
<h3 className="text-xl font-semibold text-gray-900 mb-1">{staff.name}</h3>
|
||||||
|
<p className="text-blue-600 font-medium">{staff.position}</p>
|
||||||
|
<p className="text-sm text-gray-500">{staff.degree}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4">
|
||||||
|
<p className="text-gray-700 text-sm leading-relaxed">{staff.bio}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Contact Info */}
|
||||||
|
<div className="mb-4 space-y-2">
|
||||||
|
<div className="flex items-center text-sm text-gray-600">
|
||||||
|
<span className="w-4 h-4 mr-2">📧</span>
|
||||||
|
<a href={`mailto:${staff.email}`} className="hover:text-blue-600 transition-colors">
|
||||||
|
{staff.email}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{staff.phone && (
|
||||||
|
<div className="flex items-center text-sm text-gray-600">
|
||||||
|
<span className="w-4 h-4 mr-2">📞</span>
|
||||||
|
<a href={`tel:${staff.phone}`} className="hover:text-blue-600 transition-colors">
|
||||||
|
{staff.phone}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Research Interests */}
|
||||||
|
<div className="mb-4">
|
||||||
|
<h4 className="text-sm font-semibold text-gray-900 mb-2">Области исследований:</h4>
|
||||||
|
<div className="flex flex-wrap gap-1">
|
||||||
|
{staff.researchInterests.map(interest => (
|
||||||
|
<span
|
||||||
|
key={interest}
|
||||||
|
className="bg-gray-100 text-gray-700 text-xs px-2 py-1 rounded"
|
||||||
|
>
|
||||||
|
{interest}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Publications */}
|
||||||
|
{staffPublications.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<h4 className="text-sm font-semibold text-gray-900 mb-2">
|
||||||
|
Публикации ({staffPublications.length}):
|
||||||
|
</h4>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{staffPublications.slice(0, 2).map(pub => (
|
||||||
|
<div key={pub.id} className="text-xs text-gray-600">
|
||||||
|
<p className="font-medium text-gray-800 line-clamp-1">{pub.title}</p>
|
||||||
|
<p className="text-gray-500">{pub.journal}, {pub.year}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{staffPublications.length > 2 && (
|
||||||
|
<p className="text-xs text-blue-600">
|
||||||
|
и еще {staffPublications.length - 2} публикаций...
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
35
frontend/src/components/Footer.tsx
Normal file
35
frontend/src/components/Footer.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
export default function Footer() {
|
||||||
|
return (
|
||||||
|
<footer className="bg-gray-800 text-white">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold mb-4">Отдел Радиофотоники</h3>
|
||||||
|
<p className="text-gray-300">
|
||||||
|
Ведущий научно-исследовательский центр в области радиофотоники и оптических технологий.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold mb-4">Контакты</h3>
|
||||||
|
<div className="text-gray-300 space-y-2">
|
||||||
|
<p>📧 info@radiophotonics.ru</p>
|
||||||
|
<p>📞 +7 (495) 123-45-67</p>
|
||||||
|
<p>📍 Москва, ул. Научная, 1</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold mb-4">Полезные ссылки</h3>
|
||||||
|
<div className="text-gray-300 space-y-2">
|
||||||
|
<p>🔗 Научные базы данных</p>
|
||||||
|
<p>🔗 Партнерские организации</p>
|
||||||
|
<p>🔗 Образовательные программы</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="border-t border-gray-700 mt-8 pt-8 text-center text-gray-400">
|
||||||
|
<p>© 2024 Отдел Радиофотоники. Все права защищены.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
)
|
||||||
|
}
|
||||||
41
frontend/src/components/Header.tsx
Normal file
41
frontend/src/components/Header.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export default function Header() {
|
||||||
|
return (
|
||||||
|
<header className="bg-white shadow-sm border-b">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="flex justify-between items-center h-16">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Link href="/" className="text-xl font-bold text-gray-900">
|
||||||
|
Отдел Радиофотоники
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<nav className="hidden md:flex space-x-8">
|
||||||
|
<Link href="/" className="text-gray-700 hover:text-blue-600 transition-colors">
|
||||||
|
Главная
|
||||||
|
</Link>
|
||||||
|
<Link href="/publications" className="text-gray-700 hover:text-blue-600 transition-colors">
|
||||||
|
Публикации
|
||||||
|
</Link>
|
||||||
|
<Link href="/staff" className="text-gray-700 hover:text-blue-600 transition-colors">
|
||||||
|
Сотрудники
|
||||||
|
</Link>
|
||||||
|
<Link href="/projects" className="text-gray-700 hover:text-blue-600 transition-colors">
|
||||||
|
Проекты
|
||||||
|
</Link>
|
||||||
|
<Link href="/contacts" className="text-gray-700 hover:text-blue-600 transition-colors">
|
||||||
|
Контакты
|
||||||
|
</Link>
|
||||||
|
</nav>
|
||||||
|
<div className="md:hidden">
|
||||||
|
<button className="text-gray-700 hover:text-blue-600">
|
||||||
|
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
}
|
||||||
172
frontend/src/lib/mockData.ts
Normal file
172
frontend/src/lib/mockData.ts
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
import { Publication, Staff, Project, News, RID, Partner } from '@/types';
|
||||||
|
|
||||||
|
export const mockPublications: Publication[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
title: 'Когерентная обработка сигналов в радиофотонных системах',
|
||||||
|
authors: ['Иванов И.И.', 'Петров П.П.', 'Сидоров С.С.'],
|
||||||
|
journal: 'Квантовая электроника',
|
||||||
|
year: 2024,
|
||||||
|
abstract: 'В работе исследуются методы когерентной обработки сигналов в современных радиофотонных системах. Предложен новый алгоритм фазовой синхронизации, обеспечивающий высокую точность измерений.',
|
||||||
|
doi: '10.1070/QEL17XXX',
|
||||||
|
pdfUrl: '/uploads/publications/coherent-processing-2024.pdf',
|
||||||
|
tags: ['радиофотоника', 'когерентная обработка', 'фазовая синхронизация'],
|
||||||
|
type: 'article'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
title: 'Микроволновые фотонные фильтры на основе кремниевых волноводов',
|
||||||
|
authors: ['Васильев В.В.', 'Козлов К.К.'],
|
||||||
|
journal: 'Оптика и спектроскопия',
|
||||||
|
year: 2024,
|
||||||
|
abstract: 'Разработаны и исследованы микроволновые фотонные фильтры на базе кремниевых волноводных структур. Достигнута высокая селективность и низкие оптические потери.',
|
||||||
|
doi: '10.1134/S0030400X24XXX',
|
||||||
|
pdfUrl: '/uploads/publications/photonic-filters-2024.pdf',
|
||||||
|
tags: ['фотонные фильтры', 'кремниевые волноводы', 'микроволновая фотоника'],
|
||||||
|
type: 'article'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
title: 'Оптические генераторы миллиметрового диапазона для 5G/6G систем',
|
||||||
|
authors: ['Александров А.А.', 'Николаев Н.Н.', 'Федоров Ф.Ф.'],
|
||||||
|
journal: 'IEEE Photonics Technology Letters',
|
||||||
|
year: 2023,
|
||||||
|
abstract: 'Представлены результаты разработки оптических генераторов миллиметрового диапазона для применения в системах мобильной связи следующего поколения.',
|
||||||
|
doi: '10.1109/LPT.2023.XXXX',
|
||||||
|
pdfUrl: '/uploads/publications/mmwave-generators-2023.pdf',
|
||||||
|
tags: ['миллиметровые волны', '5G', '6G', 'оптические генераторы'],
|
||||||
|
type: 'article'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const mockStaff: Staff[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
name: 'Иванов Иван Иванович',
|
||||||
|
position: 'Заведующий отделом',
|
||||||
|
email: 'ivanov@radiophotonics.ru',
|
||||||
|
phone: '+7 (495) 123-45-67',
|
||||||
|
photo: '/uploads/staff/ivanov.jpg',
|
||||||
|
bio: 'Доктор физико-математических наук, профессор. Специалист в области радиофотоники и оптических телекоммуникаций. Автор более 150 научных работ.',
|
||||||
|
publications: ['1', '2'],
|
||||||
|
researchInterests: ['радиофотоника', 'оптические телекоммуникации', 'когерентная оптика'],
|
||||||
|
degree: 'д.ф.-м.н.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
name: 'Петров Петр Петрович',
|
||||||
|
position: 'Ведущий научный сотрудник',
|
||||||
|
email: 'petrov@radiophotonics.ru',
|
||||||
|
phone: '+7 (495) 123-45-68',
|
||||||
|
photo: '/uploads/staff/petrov.jpg',
|
||||||
|
bio: 'Кандидат физико-математических наук. Специализируется на микроволновой фотонике и интегральной оптике.',
|
||||||
|
publications: ['1', '3'],
|
||||||
|
researchInterests: ['микроволновая фотоника', 'интегральная оптика', 'оптоэлектроника'],
|
||||||
|
degree: 'к.ф.-м.н.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
name: 'Сидорова Анна Сергеевна',
|
||||||
|
position: 'Старший научный сотрудник',
|
||||||
|
email: 'sidorova@radiophotonics.ru',
|
||||||
|
phone: '+7 (495) 123-45-69',
|
||||||
|
photo: '/uploads/staff/sidorova.jpg',
|
||||||
|
bio: 'Кандидат технических наук. Работает в области фотонных сенсоров и оптических измерительных систем.',
|
||||||
|
publications: ['2'],
|
||||||
|
researchInterests: ['фотонные сенсоры', 'оптические измерения', 'волоконная оптика'],
|
||||||
|
degree: 'к.т.н.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const mockProjects: Project[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
title: 'Разработка радиофотонных систем для 6G сетей',
|
||||||
|
description: 'Исследование и создание передовых радиофотонных технологий для беспроводных сетей шестого поколения, обеспечивающих высокую скорость передачи данных и низкую задержку.',
|
||||||
|
status: 'active',
|
||||||
|
startDate: '2023-01-01',
|
||||||
|
endDate: '2025-12-31',
|
||||||
|
team: ['1', '2', '3'],
|
||||||
|
publications: ['3'],
|
||||||
|
partners: ['Huawei', 'Nokia'],
|
||||||
|
funding: 'РФФИ, грант №23-07-00123',
|
||||||
|
image: '/uploads/projects/6g-networks.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
title: 'Квантовые коммуникации на основе фотонных кристаллов',
|
||||||
|
description: 'Разработка новых подходов к квантовым коммуникациям с использованием фотонных кристаллических структур для повышения безопасности передачи информации.',
|
||||||
|
status: 'active',
|
||||||
|
startDate: '2022-06-01',
|
||||||
|
endDate: '2024-12-31',
|
||||||
|
team: ['1', '3'],
|
||||||
|
publications: ['1', '2'],
|
||||||
|
funding: 'РНФ, грант №22-12-00456',
|
||||||
|
image: '/uploads/projects/quantum-comm.jpg'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const mockNews: News[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
title: 'Отдел радиофотоники получил грант РНФ на исследование квантовых коммуникаций',
|
||||||
|
content: 'Коллектив отдела успешно выиграл конкурс Российского научного фонда и получил финансирование на трехлетний проект по разработке квантовых коммуникационных систем.',
|
||||||
|
date: '2024-01-15',
|
||||||
|
author: 'Иванов И.И.',
|
||||||
|
image: '/uploads/news/grant-rnf.jpg',
|
||||||
|
tags: ['гранты', 'квантовые коммуникации', 'РНФ']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
title: 'Публикация в высокорейтинговом журнале IEEE',
|
||||||
|
content: 'Статья сотрудников отдела о микроволновых фотонных фильтрах опубликована в престижном международном журнале IEEE Photonics Technology Letters.',
|
||||||
|
date: '2024-02-10',
|
||||||
|
author: 'Петров П.П.',
|
||||||
|
image: '/uploads/news/ieee-publication.jpg',
|
||||||
|
tags: ['публикации', 'IEEE', 'фотонные фильтры']
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const mockRIDs: RID[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
title: 'Способ формирования радиофотонного сигнала с низким фазовым шумом',
|
||||||
|
type: 'patent',
|
||||||
|
registrationNumber: 'RU 2745123 C1',
|
||||||
|
registrationDate: '2021-03-22',
|
||||||
|
authors: ['Иванов И.И.', 'Петров П.П.'],
|
||||||
|
description: 'Изобретение относится к области радиофотоники и может быть использовано для создания высокостабильных генераторов.',
|
||||||
|
status: 'registered'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
title: 'Программа моделирования фотонных интегральных схем',
|
||||||
|
type: 'software',
|
||||||
|
registrationNumber: '2023612345',
|
||||||
|
registrationDate: '2023-04-15',
|
||||||
|
authors: ['Сидорова А.С.', 'Васильев В.В.'],
|
||||||
|
description: 'Программное обеспечение для проектирования и моделирования фотонных интегральных схем.',
|
||||||
|
status: 'registered'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const mockPartners: Partner[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
name: 'Huawei Technologies',
|
||||||
|
logo: '/uploads/partners/huawei-logo.png',
|
||||||
|
website: 'https://www.huawei.com',
|
||||||
|
description: 'Совместные исследования в области 5G/6G технологий и радиофотоники.',
|
||||||
|
collaborationType: ['исследования', 'разработка'],
|
||||||
|
projects: ['1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
name: 'ООО "ОптЛинк"',
|
||||||
|
logo: '/uploads/partners/optlink-logo.png',
|
||||||
|
website: 'https://optlink.ru',
|
||||||
|
description: 'Российская компания, специализирующаяся на производстве оптоэлектронных компонентов.',
|
||||||
|
collaborationType: ['производство', 'внедрение'],
|
||||||
|
projects: ['2']
|
||||||
|
}
|
||||||
|
];
|
||||||
70
frontend/src/types/index.ts
Normal file
70
frontend/src/types/index.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
export interface Publication {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
authors: string[];
|
||||||
|
journal: string;
|
||||||
|
year: number;
|
||||||
|
abstract: string;
|
||||||
|
doi?: string;
|
||||||
|
pdfUrl?: string;
|
||||||
|
tags: string[];
|
||||||
|
type: 'article' | 'conference' | 'book' | 'patent';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Staff {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
position: string;
|
||||||
|
email: string;
|
||||||
|
phone?: string;
|
||||||
|
photo: string;
|
||||||
|
bio: string;
|
||||||
|
publications: string[];
|
||||||
|
researchInterests: string[];
|
||||||
|
degree: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Project {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
status: 'active' | 'completed' | 'planned';
|
||||||
|
startDate: string;
|
||||||
|
endDate?: string;
|
||||||
|
team: string[];
|
||||||
|
publications: string[];
|
||||||
|
partners?: string[];
|
||||||
|
funding?: string;
|
||||||
|
image?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface News {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
date: string;
|
||||||
|
author: string;
|
||||||
|
image?: string;
|
||||||
|
tags: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RID {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
type: 'patent' | 'software' | 'database' | 'method';
|
||||||
|
registrationNumber?: string;
|
||||||
|
registrationDate?: string;
|
||||||
|
authors: string[];
|
||||||
|
description: string;
|
||||||
|
status: 'registered' | 'pending' | 'application';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Partner {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
logo: string;
|
||||||
|
website?: string;
|
||||||
|
description: string;
|
||||||
|
collaborationType: string[];
|
||||||
|
projects: string[];
|
||||||
|
}
|
||||||
27
frontend/tsconfig.json
Normal file
27
frontend/tsconfig.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2017",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"incremental": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "ru.radiophotonics",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user