Improve SEO

This commit is contained in:
2025-07-17 23:18:50 +03:00
parent 0c938231df
commit 86dc57af01
7 changed files with 129 additions and 1 deletions

8
next-sitemap.config.js Normal file
View File

@@ -0,0 +1,8 @@
/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: 'https://neomovies.ru',
generateRobotsTxt: true, // создает robots.txt
sitemapSize: 7000,
// игнорируем служебные пути
exclude: ['/admin', '/auth'],
};

View File

@@ -5,10 +5,12 @@
"scripts": { "scripts": {
"dev": "next dev --turbopack", "dev": "next dev --turbopack",
"build": "next build", "build": "next build",
"postbuild": "next-sitemap",
"start": "next start", "start": "next start",
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@radix-ui/react-slot": "^1.2.3",
"@reduxjs/toolkit": "^2.5.0", "@reduxjs/toolkit": "^2.5.0",
"@tabler/icons-react": "^3.26.0", "@tabler/icons-react": "^3.26.0",
"@types/bcrypt": "^5.0.2", "@types/bcrypt": "^5.0.2",
@@ -21,7 +23,9 @@
"axios": "^1.7.9", "axios": "^1.7.9",
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"class-variance-authority": "^0.7.1",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"clsx": "^2.1.1",
"framer-motion": "^11.15.0", "framer-motion": "^11.15.0",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
@@ -29,6 +33,7 @@
"mongodb": "^6.12.0", "mongodb": "^6.12.0",
"mongoose": "^8.9.2", "mongoose": "^8.9.2",
"next": "15.1.2", "next": "15.1.2",
"next-seo": "^6.8.0",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"nodemailer": "^6.9.16", "nodemailer": "^6.9.16",
"react": "^19.0.0", "react": "^19.0.0",
@@ -38,7 +43,8 @@
"react-redux": "^9.2.0", "react-redux": "^9.2.0",
"resend": "^4.0.1", "resend": "^4.0.1",
"styled-components": "^6.1.13", "styled-components": "^6.1.13",
"tailwind": "^4.0.0" "tailwind": "^4.0.0",
"tailwind-merge": "^3.3.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3", "@eslint/eslintrc": "^3",
@@ -47,6 +53,7 @@
"@types/react-dom": "^19", "@types/react-dom": "^19",
"eslint": "^9", "eslint": "^9",
"eslint-config-next": "15.1.2", "eslint-config-next": "15.1.2",
"next-sitemap": "^4.2.3",
"postcss": "^8", "postcss": "^8",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"typescript": "^5" "typescript": "^5"

21
public/manifest.json Normal file
View File

@@ -0,0 +1,21 @@
{
"name": "NeoMovies",
"short_name": "NeoMovies",
"start_url": "/",
"display": "standalone",
"background_color": "#000000",
"theme_color": "#000000",
"description": "Смотрите фильмы и сериалы онлайн на NeoMovies.",
"icons": [
{
"src": "/public/logo.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/public/logo.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

View File

@@ -1,6 +1,8 @@
import { Inter } from 'next/font/google'; import { Inter } from 'next/font/google';
import Script from 'next/script'; import Script from 'next/script';
import './globals.css'; import './globals.css';
import { DefaultSeo } from 'next-seo';
import SEO from '@/next-seo.config';
import { ClientLayout } from '@/components/ClientLayout'; import { ClientLayout } from '@/components/ClientLayout';
import { Providers } from '@/components/Providers'; import { Providers } from '@/components/Providers';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
@@ -23,6 +25,9 @@ export default function RootLayout({
<html lang="ru"> <html lang="ru">
<head> <head>
<meta name="darkreader-lock" /> <meta name="darkreader-lock" />
<link rel="icon" href="/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/public/logo.png" />
<link rel="manifest" href="/manifest.json" />
{/* Google tag (gtag.js) */} {/* Google tag (gtag.js) */}
<Script <Script
@@ -61,6 +66,7 @@ export default function RootLayout({
></iframe> ></iframe>
</noscript> </noscript>
{/* End Google Tag Manager (noscript) */} {/* End Google Tag Manager (noscript) */}
<DefaultSeo {...SEO} />
<Providers> <Providers>
<ClientLayout>{children}</ClientLayout> <ClientLayout>{children}</ClientLayout>
</Providers> </Providers>

View File

@@ -11,6 +11,7 @@ import FavoriteButton from '@/components/FavoriteButton';
import Reactions from '@/components/Reactions'; import Reactions from '@/components/Reactions';
import { formatDate } from '@/lib/utils'; import { formatDate } from '@/lib/utils';
import { PlayCircle, ArrowLeft } from 'lucide-react'; import { PlayCircle, ArrowLeft } from 'lucide-react';
import { NextSeo } from 'next-seo';
interface MovieContentProps { interface MovieContentProps {
movieId: string; movieId: string;
@@ -62,6 +63,39 @@ export default function MovieContent({ movieId, initialMovie }: MovieContentProp
return ( return (
<> <>
<NextSeo
title={`${movie.title} смотреть онлайн`}
description={movie.overview?.slice(0, 150)}
canonical={`https://neomovies.ru/movie/${movie.id}`}
openGraph={{
url: `https://neomovies.ru/movie/${movie.id}`,
images: [
{
url: getImageUrl(movie.poster_path, 'w780'),
alt: movie.title,
},
],
}}
/>
{/* schema.org Movie */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Movie',
name: movie.title,
image: getImageUrl(movie.poster_path, 'w780'),
description: movie.overview,
datePublished: movie.release_date,
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: movie.vote_average,
ratingCount: movie.vote_count,
},
}),
}}
/>
<div className="min-h-screen bg-background text-foreground px-4 py-6 md:px-6 lg:px-8"> <div className="min-h-screen bg-background text-foreground px-4 py-6 md:px-6 lg:px-8">
<div className="w-full"> <div className="w-full">
<div className="grid grid-cols-1 gap-8 md:grid-cols-3"> <div className="grid grid-cols-1 gap-8 md:grid-cols-3">

View File

@@ -11,6 +11,7 @@ import FavoriteButton from '@/components/FavoriteButton';
import Reactions from '@/components/Reactions'; import Reactions from '@/components/Reactions';
import { formatDate } from '@/lib/utils'; import { formatDate } from '@/lib/utils';
import { PlayCircle, ArrowLeft } from 'lucide-react'; import { PlayCircle, ArrowLeft } from 'lucide-react';
import { NextSeo } from 'next-seo';
interface TVContentProps { interface TVContentProps {
showId: string; showId: string;
@@ -69,6 +70,39 @@ export default function TVContent({ showId, initialShow }: TVContentProps) {
return ( return (
<> <>
<NextSeo
title={`${show.name} смотреть онлайн`}
description={show.overview?.slice(0, 150)}
canonical={`https://neomovies.ru/tv/${show.id}`}
openGraph={{
url: `https://neomovies.ru/tv/${show.id}`,
images: [
{
url: getImageUrl(show.poster_path, 'w780'),
alt: show.name,
},
],
}}
/>
{/* schema.org TVSeries */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'TVSeries',
name: show.name,
image: getImageUrl(show.poster_path, 'w780'),
description: show.overview,
numberOfSeasons: show.number_of_seasons,
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: show.vote_average,
ratingCount: show.vote_count,
},
}),
}}
/>
<div className="min-h-screen bg-background text-foreground px-4 py-6 md:px-6 lg:px-8"> <div className="min-h-screen bg-background text-foreground px-4 py-6 md:px-6 lg:px-8">
<div className="w-full"> <div className="w-full">
<div className="grid grid-cols-1 gap-8 md:grid-cols-3"> <div className="grid grid-cols-1 gap-8 md:grid-cols-3">

18
src/next-seo.config.ts Normal file
View File

@@ -0,0 +1,18 @@
const SEO = {
titleTemplate: "%s | NeoMovies",
defaultTitle: "NeoMovies смотреть фильмы и сериалы онлайн",
description:
"Смотрите фильмы и сериалы в хорошем качестве без регистрации NeoMovies.",
canonical: "https://neomovies.ru",
openGraph: {
type: "website",
locale: "ru_RU",
url: "https://neomovies.ru",
siteName: "NeoMovies",
},
twitter: {
cardType: "summary_large_image",
},
};
export default SEO;