udpdates
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
* Used across all Planner and Writer module pages
|
* Used across all Planner and Writer module pages
|
||||||
* Includes: Page title, last updated, site/sector info, and selectors
|
* Includes: Page title, last updated, site/sector info, and selectors
|
||||||
*/
|
*/
|
||||||
|
import React, { ReactNode } from 'react';
|
||||||
import { useSiteStore } from '../../store/siteStore';
|
import { useSiteStore } from '../../store/siteStore';
|
||||||
import { useSectorStore } from '../../store/sectorStore';
|
import { useSectorStore } from '../../store/sectorStore';
|
||||||
import SiteAndSectorSelector from './SiteAndSectorSelector';
|
import SiteAndSectorSelector from './SiteAndSectorSelector';
|
||||||
@@ -13,6 +14,10 @@ interface PageHeaderProps {
|
|||||||
showRefresh?: boolean;
|
showRefresh?: boolean;
|
||||||
onRefresh?: () => void;
|
onRefresh?: () => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
badge?: {
|
||||||
|
icon: ReactNode;
|
||||||
|
color: 'blue' | 'green' | 'purple' | 'orange' | 'red' | 'indigo';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PageHeader({
|
export default function PageHeader({
|
||||||
@@ -21,14 +26,33 @@ export default function PageHeader({
|
|||||||
showRefresh = false,
|
showRefresh = false,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
className = "",
|
className = "",
|
||||||
|
badge,
|
||||||
}: PageHeaderProps) {
|
}: PageHeaderProps) {
|
||||||
const { activeSite } = useSiteStore();
|
const { activeSite } = useSiteStore();
|
||||||
const { activeSector } = useSectorStore();
|
const { activeSector } = useSectorStore();
|
||||||
|
|
||||||
|
const badgeColors = {
|
||||||
|
blue: 'bg-blue-600 dark:bg-blue-500',
|
||||||
|
green: 'bg-green-600 dark:bg-green-500',
|
||||||
|
purple: 'bg-purple-600 dark:bg-purple-500',
|
||||||
|
orange: 'bg-orange-600 dark:bg-orange-500',
|
||||||
|
red: 'bg-red-600 dark:bg-red-500',
|
||||||
|
indigo: 'bg-indigo-600 dark:bg-indigo-500',
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 ${className}`}>
|
<div className={`flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 ${className}`}>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<h2 className="text-2xl font-bold text-gray-800 dark:text-white/90">{title}</h2>
|
<div className="flex items-center gap-3">
|
||||||
|
{badge && (
|
||||||
|
<div className={`flex items-center justify-center w-10 h-10 rounded-xl ${badgeColors[badge.color]} flex-shrink-0`}>
|
||||||
|
{badge.icon && typeof badge.icon === 'object' && 'type' in badge.icon
|
||||||
|
? React.cloneElement(badge.icon as React.ReactElement, { className: 'text-white size-5' })
|
||||||
|
: badge.icon}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<h2 className="text-2xl font-bold text-gray-800 dark:text-white/90">{title}</h2>
|
||||||
|
</div>
|
||||||
<div className="flex items-center gap-3 mt-1">
|
<div className="flex items-center gap-3 mt-1">
|
||||||
{lastUpdated && (
|
{lastUpdated && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -385,11 +385,12 @@ export default function Clusters() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title="Keyword Clusters" />
|
<PageHeader
|
||||||
|
title="Keyword Clusters"
|
||||||
|
badge={{ icon: <GroupIcon />, color: 'green' }}
|
||||||
|
/>
|
||||||
<TablePageTemplate
|
<TablePageTemplate
|
||||||
title="Keyword Clusters"
|
hideHeader={true}
|
||||||
titleIcon={<GroupIcon className="text-success-500 size-5" />}
|
|
||||||
subtitle="Organize keywords into content clusters for better SEO strategy"
|
|
||||||
columns={pageConfig.columns}
|
columns={pageConfig.columns}
|
||||||
data={clusters}
|
data={clusters}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|||||||
@@ -473,6 +473,7 @@ export default function PlannerDashboard() {
|
|||||||
lastUpdated={lastUpdated}
|
lastUpdated={lastUpdated}
|
||||||
showRefresh={true}
|
showRefresh={true}
|
||||||
onRefresh={fetchDashboardData}
|
onRefresh={fetchDashboardData}
|
||||||
|
badge={{ icon: <PieChartIcon />, color: 'blue' }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Hero Section - Key Metric */}
|
{/* Hero Section - Key Metric */}
|
||||||
|
|||||||
@@ -295,11 +295,12 @@ export default function Ideas() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title="Content Ideas" />
|
<PageHeader
|
||||||
|
title="Content Ideas"
|
||||||
|
badge={{ icon: <BoltIcon />, color: 'orange' }}
|
||||||
|
/>
|
||||||
<TablePageTemplate
|
<TablePageTemplate
|
||||||
title="Content Ideas"
|
hideHeader={true}
|
||||||
titleIcon={<BoltIcon className="text-warning-500 size-5" />}
|
|
||||||
subtitle="Generate and organize content ideas based on keyword research"
|
|
||||||
columns={pageConfig.columns}
|
columns={pageConfig.columns}
|
||||||
data={ideas}
|
data={ideas}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|||||||
@@ -752,11 +752,12 @@ export default function Keywords() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title="Keywords" />
|
<PageHeader
|
||||||
|
title="Keywords"
|
||||||
|
badge={{ icon: <ListIcon />, color: 'blue' }}
|
||||||
|
/>
|
||||||
<TablePageTemplate
|
<TablePageTemplate
|
||||||
title="Keywords"
|
hideHeader={true}
|
||||||
titleIcon={<ListIcon className="text-brand-500 size-5" />}
|
|
||||||
subtitle="Manage and organize SEO keywords for content planning"
|
|
||||||
columns={pageConfig.columns}
|
columns={pageConfig.columns}
|
||||||
data={keywords}
|
data={keywords}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import PageMeta from "../../components/common/PageMeta";
|
import PageMeta from "../../components/common/PageMeta";
|
||||||
import ComponentCard from "../../components/common/ComponentCard";
|
import ComponentCard from "../../components/common/ComponentCard";
|
||||||
import PageHeader from "../../components/common/PageHeader";
|
import PageHeader from "../../components/common/PageHeader";
|
||||||
|
import { PieChartIcon } from "../../icons";
|
||||||
|
|
||||||
export default function Mapping() {
|
export default function Mapping() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageMeta title="Content Mapping - IGNY8" description="Keyword to content mapping" />
|
<PageMeta title="Content Mapping - IGNY8" description="Keyword to content mapping" />
|
||||||
<PageHeader title="Content Mapping" />
|
<PageHeader
|
||||||
|
title="Content Mapping"
|
||||||
|
badge={{ icon: <PieChartIcon />, color: 'indigo' }}
|
||||||
|
/>
|
||||||
<ComponentCard title="Coming Soon" desc="Keyword to content mapping">
|
<ComponentCard title="Coming Soon" desc="Keyword to content mapping">
|
||||||
<div className="text-center py-8">
|
<div className="text-center py-8">
|
||||||
<p className="text-gray-600 dark:text-gray-400">
|
<p className="text-gray-600 dark:text-gray-400">
|
||||||
|
|||||||
@@ -181,11 +181,12 @@ export default function Content() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title="Content" />
|
<PageHeader
|
||||||
|
title="Content"
|
||||||
|
badge={{ icon: <FileIcon />, color: 'purple' }}
|
||||||
|
/>
|
||||||
<TablePageTemplate
|
<TablePageTemplate
|
||||||
title="Content"
|
hideHeader={true}
|
||||||
titleIcon={<FileIcon className="text-brand-500 size-5" />}
|
|
||||||
subtitle="Review AI-generated content and metadata"
|
|
||||||
columns={pageConfig.columns}
|
columns={pageConfig.columns}
|
||||||
data={content}
|
data={content}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|||||||
@@ -552,6 +552,7 @@ export default function WriterDashboard() {
|
|||||||
lastUpdated={lastUpdated}
|
lastUpdated={lastUpdated}
|
||||||
showRefresh={true}
|
showRefresh={true}
|
||||||
onRefresh={fetchDashboardData}
|
onRefresh={fetchDashboardData}
|
||||||
|
badge={{ icon: <PencilIcon />, color: 'green' }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Hero Section - Key Metric */}
|
{/* Hero Section - Key Metric */}
|
||||||
|
|||||||
@@ -385,11 +385,12 @@ export default function Images() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title="Content Images" />
|
<PageHeader
|
||||||
|
title="Content Images"
|
||||||
|
badge={{ icon: <FileIcon />, color: 'purple' }}
|
||||||
|
/>
|
||||||
<TablePageTemplate
|
<TablePageTemplate
|
||||||
title="Content Images"
|
hideHeader={true}
|
||||||
titleIcon={<FileIcon className="text-purple-500 size-5" />}
|
|
||||||
subtitle="Manage images for content articles"
|
|
||||||
columns={pageConfig.columns}
|
columns={pageConfig.columns}
|
||||||
data={images}
|
data={images}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|||||||
@@ -711,9 +711,7 @@ export default function Tasks() {
|
|||||||
<ViewToggle currentView={currentView} onViewChange={setCurrentView} />
|
<ViewToggle currentView={currentView} onViewChange={setCurrentView} />
|
||||||
</div>
|
</div>
|
||||||
<TablePageTemplate
|
<TablePageTemplate
|
||||||
title="Tasks"
|
hideHeader={true}
|
||||||
titleIcon={<TaskIcon className="text-brand-500 size-5" />}
|
|
||||||
subtitle="Manage content generation queue and tasks"
|
|
||||||
columns={pageConfig.columns}
|
columns={pageConfig.columns}
|
||||||
data={tasks}
|
data={tasks}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|||||||
@@ -82,9 +82,10 @@ interface HeaderMetrics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface TablePageTemplateProps {
|
interface TablePageTemplateProps {
|
||||||
title: string;
|
title?: string; // Optional - hide if PageHeader is used
|
||||||
titleIcon?: ReactNode; // Icon component for title (e.g., ListIcon)
|
titleIcon?: ReactNode; // Icon component for title (e.g., ListIcon)
|
||||||
subtitle?: string;
|
subtitle?: string; // Optional - hide if PageHeader is used
|
||||||
|
hideHeader?: boolean; // Hide the header section when PageHeader is used
|
||||||
columns: ColumnConfig[];
|
columns: ColumnConfig[];
|
||||||
data: any[];
|
data: any[];
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
@@ -504,28 +505,32 @@ export default function TablePageTemplate({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
{/* Page Header - Match Keywords.tsx styling */}
|
{/* Page Header - Match Keywords.tsx styling - Hide if hideHeader is true */}
|
||||||
<div className="flex justify-between items-center mb-6 overflow-visible">
|
{!hideHeader && (
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex justify-between items-center mb-6 overflow-visible">
|
||||||
<h2 className="text-xl font-semibold text-gray-800 dark:text-white/90 flex items-center gap-2">
|
<div className="flex-1 min-w-0">
|
||||||
{titleIcon && (
|
{title && (
|
||||||
<div className="flex items-center justify-center w-10 h-10 bg-blue-50 rounded-xl dark:bg-blue-500/10">
|
<h2 className="text-xl font-semibold text-gray-800 dark:text-white/90 flex items-center gap-2">
|
||||||
{titleIcon}
|
{titleIcon && (
|
||||||
</div>
|
<div className="flex items-center justify-center w-10 h-10 bg-blue-50 rounded-xl dark:bg-blue-500/10">
|
||||||
|
{titleIcon}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
)}
|
)}
|
||||||
{title}
|
{subtitle && (
|
||||||
</h2>
|
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||||
{subtitle && (
|
{subtitle}
|
||||||
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
</p>
|
||||||
{subtitle}
|
)}
|
||||||
</p>
|
</div>
|
||||||
)}
|
{/* Sector Selector - Replaces notification card */}
|
||||||
|
<div className="flex-shrink-0 overflow-visible">
|
||||||
|
<SectorSelector />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Sector Selector - Replaces notification card */}
|
)}
|
||||||
<div className="flex-shrink-0 overflow-visible">
|
|
||||||
<SectorSelector />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Filters Row - 75% centered, container inside stretched to 100% */}
|
{/* Filters Row - 75% centered, container inside stretched to 100% */}
|
||||||
{(renderFilters || filters.length > 0) && (
|
{(renderFilters || filters.length > 0) && (
|
||||||
|
|||||||
Reference in New Issue
Block a user