mirror of
https://git.meshkee.com/novintrades/website.git
synced 2026-08-11 20:50:58 +04:30
Add SEO meta descriptions and a dynamic sitemap.
Expose optional metaDescription for blogs, reportages, and brands in admin/API, apply it on detail pages, and serve an up-to-date /sitemap.xml for approved content plus static site pages. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
5088e0f4ae
commit
16bc154fb0
@@ -32,6 +32,7 @@ export function getBlog(id: string) {
|
||||
export function createBlog(input: {
|
||||
title: string;
|
||||
abstract?: string;
|
||||
metaDescription?: string;
|
||||
content?: string;
|
||||
imageUrl?: string | null;
|
||||
tags?: string[];
|
||||
@@ -50,6 +51,7 @@ export function updateBlog(
|
||||
input: {
|
||||
title?: string;
|
||||
abstract?: string;
|
||||
metaDescription?: string;
|
||||
content?: string;
|
||||
imageUrl?: string | null;
|
||||
tags?: string[];
|
||||
@@ -76,6 +78,7 @@ export function createReportage(input: {
|
||||
title: string;
|
||||
businessOwner: string;
|
||||
abstract?: string;
|
||||
metaDescription?: string;
|
||||
content?: string;
|
||||
imageUrl?: string | null;
|
||||
tags?: string[];
|
||||
@@ -95,6 +98,7 @@ export function updateReportage(
|
||||
title?: string;
|
||||
businessOwner?: string;
|
||||
abstract?: string;
|
||||
metaDescription?: string;
|
||||
content?: string;
|
||||
imageUrl?: string | null;
|
||||
tags?: string[];
|
||||
@@ -120,6 +124,7 @@ export function getBrand(id: string) {
|
||||
export function createBrand(input: {
|
||||
title: string;
|
||||
abstract?: string;
|
||||
metaDescription?: string;
|
||||
content?: string;
|
||||
imageUrl?: string | null;
|
||||
galleryUrls?: string[];
|
||||
@@ -143,6 +148,7 @@ export function updateBrand(
|
||||
input: {
|
||||
title?: string;
|
||||
abstract?: string;
|
||||
metaDescription?: string;
|
||||
content?: string;
|
||||
imageUrl?: string | null;
|
||||
galleryUrls?: string[];
|
||||
|
||||
@@ -24,6 +24,7 @@ export interface Blog {
|
||||
title: string;
|
||||
slug: string;
|
||||
abstract: string | null;
|
||||
metaDescription: string | null;
|
||||
content: string;
|
||||
imageUrl: string | null;
|
||||
tags: string[];
|
||||
@@ -42,6 +43,7 @@ export interface Reportage {
|
||||
slug: string;
|
||||
businessOwner: string;
|
||||
abstract: string | null;
|
||||
metaDescription: string | null;
|
||||
content: string;
|
||||
imageUrl: string | null;
|
||||
tags: string[];
|
||||
@@ -71,6 +73,7 @@ export interface Brand {
|
||||
title: string;
|
||||
slug: string;
|
||||
abstract: string | null;
|
||||
metaDescription: string | null;
|
||||
content: string;
|
||||
imageUrl: string | null;
|
||||
galleryUrls: string[];
|
||||
|
||||
@@ -28,6 +28,7 @@ export function BlogNewPage() {
|
||||
const [title, setTitle] = useState("");
|
||||
const [image, setImage] = useState<string | null>(null);
|
||||
const [abstract, setAbstract] = useState("");
|
||||
const [metaDescription, setMetaDescription] = useState("");
|
||||
const [content, setContent] = useState("");
|
||||
const [tags, setTags] = useState<string[]>([]);
|
||||
const [error, setError] = useState("");
|
||||
@@ -49,6 +50,7 @@ export function BlogNewPage() {
|
||||
if (cancelled) return;
|
||||
setTitle(blog.title);
|
||||
setAbstract(blog.abstract ?? "");
|
||||
setMetaDescription(blog.metaDescription ?? "");
|
||||
setContent(blog.content);
|
||||
setImage(blog.imageUrl);
|
||||
setTags(blog.tags);
|
||||
@@ -86,6 +88,7 @@ export function BlogNewPage() {
|
||||
const payload = {
|
||||
title: title.trim(),
|
||||
abstract: abstract.trim() || undefined,
|
||||
metaDescription: metaDescription.trim() || undefined,
|
||||
content,
|
||||
imageUrl: image,
|
||||
tags,
|
||||
@@ -175,6 +178,20 @@ export function BlogNewPage() {
|
||||
placeholder="Short summary shown in lists and previews"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<label className="field__label" htmlFor="post-meta-description">
|
||||
Meta description
|
||||
</label>
|
||||
<textarea
|
||||
id="post-meta-description"
|
||||
className="field-textarea"
|
||||
value={metaDescription}
|
||||
onChange={(e) => setMetaDescription(e.target.value)}
|
||||
placeholder="SEO description for search engines (recommended under 160 characters)"
|
||||
maxLength={300}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ export function BrandNewPage() {
|
||||
const [categories, setCategories] = useState<string[]>([]);
|
||||
const [name, setName] = useState("");
|
||||
const [about, setAbout] = useState("");
|
||||
const [metaDescription, setMetaDescription] = useState("");
|
||||
const [image, setImage] = useState<string | null>(null);
|
||||
const [gallery, setGallery] = useState<string[]>([]);
|
||||
const [content, setContent] = useState("");
|
||||
@@ -76,6 +77,7 @@ export function BrandNewPage() {
|
||||
if (cancelled) return;
|
||||
setName(brand.title);
|
||||
setAbout(brand.abstract ?? "");
|
||||
setMetaDescription(brand.metaDescription ?? "");
|
||||
setContent(brand.content);
|
||||
setImage(brand.imageUrl);
|
||||
setGallery(brand.galleryUrls ?? []);
|
||||
@@ -118,6 +120,7 @@ export function BrandNewPage() {
|
||||
const payload = {
|
||||
title: name.trim(),
|
||||
abstract: about.trim() || undefined,
|
||||
metaDescription: metaDescription.trim() || undefined,
|
||||
content,
|
||||
imageUrl: image,
|
||||
galleryUrls: gallery,
|
||||
@@ -214,6 +217,20 @@ export function BrandNewPage() {
|
||||
placeholder="Short description of the business"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<label className="field__label" htmlFor="brand-meta-description">
|
||||
Meta description
|
||||
</label>
|
||||
<textarea
|
||||
id="brand-meta-description"
|
||||
className="field-textarea"
|
||||
value={metaDescription}
|
||||
onChange={(e) => setMetaDescription(e.target.value)}
|
||||
placeholder="SEO description for search engines (recommended under 160 characters)"
|
||||
maxLength={300}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ export function ReportageNewPage() {
|
||||
const [businessOwner, setBusinessOwner] = useState("");
|
||||
const [image, setImage] = useState<string | null>(null);
|
||||
const [abstract, setAbstract] = useState("");
|
||||
const [metaDescription, setMetaDescription] = useState("");
|
||||
const [content, setContent] = useState("");
|
||||
const [tags, setTags] = useState<string[]>([]);
|
||||
const [error, setError] = useState("");
|
||||
@@ -51,6 +52,7 @@ export function ReportageNewPage() {
|
||||
setTitle(reportage.title);
|
||||
setBusinessOwner(reportage.businessOwner);
|
||||
setAbstract(reportage.abstract ?? "");
|
||||
setMetaDescription(reportage.metaDescription ?? "");
|
||||
setContent(reportage.content);
|
||||
setImage(reportage.imageUrl);
|
||||
setTags(reportage.tags);
|
||||
@@ -91,6 +93,7 @@ export function ReportageNewPage() {
|
||||
title: title.trim(),
|
||||
businessOwner: businessOwner.trim(),
|
||||
abstract: abstract.trim() || undefined,
|
||||
metaDescription: metaDescription.trim() || undefined,
|
||||
content,
|
||||
imageUrl: image,
|
||||
tags,
|
||||
@@ -194,6 +197,20 @@ export function ReportageNewPage() {
|
||||
placeholder="Short summary for listings"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<label className="field__label" htmlFor="reportage-meta-description">
|
||||
Meta description
|
||||
</label>
|
||||
<textarea
|
||||
id="reportage-meta-description"
|
||||
className="field-textarea"
|
||||
value={metaDescription}
|
||||
onChange={(e) => setMetaDescription(e.target.value)}
|
||||
placeholder="SEO description for search engines (recommended under 160 characters)"
|
||||
maxLength={300}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user