COmpoeentes standardization 2
@@ -97,8 +97,7 @@ export default function PaymentHistory() {
|
||||
<h2 className="text-2xl font-semibold text-gray-900 dark:text-white">
|
||||
Payment History
|
||||
</h2>
|
||||
<Button onClick={loadPayments} variant="outline" size="sm">
|
||||
<RefreshCwIcon className="w-4 h-4 mr-2" />
|
||||
<Button onClick={loadPayments} variant="outline" size="sm" startIcon={<RefreshCwIcon className="w-4 h-4" />}>
|
||||
Refresh
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,9 @@ import Switch from '../form/switch/Switch';
|
||||
import Button from '../ui/button/Button';
|
||||
import Badge from '../ui/badge/Badge';
|
||||
import SiteSetupChecklist from '../sites/SiteSetupChecklist';
|
||||
import SiteTypeBadge from '../sites/SiteTypeBadge';
|
||||
import { Site } from '../../services/api';
|
||||
import { BoxCubeIcon as SettingsIcon, EyeIcon, FileIcon } from '../../icons';
|
||||
|
||||
interface SiteCardProps {
|
||||
site: Site;
|
||||
@@ -68,16 +70,17 @@ export default function SiteCard({
|
||||
</p>
|
||||
)}
|
||||
<div className="flex items-center gap-2 mb-2 flex-wrap">
|
||||
<SiteTypeBadge hostingType={site.hosting_type} />
|
||||
{site.industry_name && (
|
||||
<Badge variant="light" color="info" className="text-xs">
|
||||
<Badge variant="soft" color="warning" size="sm">
|
||||
{site.industry_name}
|
||||
</Badge>
|
||||
)}
|
||||
<Badge variant="light" color="info" className="text-xs">
|
||||
<Badge variant="soft" color="neutral" size="sm">
|
||||
{site.active_sectors_count} / 5 Sectors
|
||||
</Badge>
|
||||
{site.status && (
|
||||
<Badge variant="light" color={site.status === 'active' ? 'success' : 'dark'} className="text-xs">
|
||||
<Badge variant={site.is_active ? 'solid' : 'soft'} color={site.status === 'active' ? 'success' : 'neutral'} size="sm">
|
||||
{site.status}
|
||||
</Badge>
|
||||
)}
|
||||
@@ -105,46 +108,34 @@ export default function SiteCard({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between border-t border-gray-200 p-5 dark:border-gray-800">
|
||||
<div className="flex gap-3">
|
||||
<div className="flex items-center justify-between border-t border-gray-200 p-4 dark:border-gray-800">
|
||||
<div className="flex gap-2 flex-1">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="md"
|
||||
onClick={() => onSettings(site)}
|
||||
title="Configure Site - Update connection details and publishing settings"
|
||||
className="shadow-theme-xs inline-flex h-11 w-11 items-center justify-center rounded-lg border border-gray-300 text-gray-700 dark:border-gray-700 dark:text-gray-400"
|
||||
variant="primary"
|
||||
tone="brand"
|
||||
size="sm"
|
||||
onClick={() => onDetails(site)}
|
||||
startIcon={<EyeIcon className="w-4 h-4" />}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M5.64615 4.59906C5.05459 4.25752 4.29808 4.46015 3.95654 5.05171L2.69321 7.23986C2.35175 7.83128 2.5544 8.58754 3.14582 8.92899C3.97016 9.40493 3.97017 10.5948 3.14583 11.0707C2.55441 11.4122 2.35178 12.1684 2.69323 12.7598L3.95657 14.948C4.2981 15.5395 5.05461 15.7422 5.64617 15.4006C6.4706 14.9247 7.50129 15.5196 7.50129 16.4715C7.50129 17.1545 8.05496 17.7082 8.73794 17.7082H11.2649C11.9478 17.7082 12.5013 17.1545 12.5013 16.4717C12.5013 15.5201 13.5315 14.9251 14.3556 15.401C14.9469 15.7423 15.7029 15.5397 16.0443 14.9485L17.3079 12.7598C17.6494 12.1684 17.4467 11.4121 16.8553 11.0707C16.031 10.5948 16.031 9.40494 16.8554 8.92902C17.4468 8.58757 17.6494 7.83133 17.3079 7.23992L16.0443 5.05123C15.7029 4.45996 14.9469 4.25737 14.3556 4.59874C13.5315 5.07456 12.5013 4.47961 12.5013 3.52798C12.5013 2.84515 11.9477 2.2915 11.2649 2.2915L8.73795 2.2915C8.05496 2.2915 7.50129 2.84518 7.50129 3.52816C7.50129 4.48015 6.47059 5.07505 5.64615 4.59906Z"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12.5714 9.99977C12.5714 11.4196 11.4204 12.5706 10.0005 12.5706C8.58069 12.5706 7.42969 11.4196 7.42969 9.99977C7.42969 8.57994 8.58069 7.42894 10.0005 7.42894C11.4204 7.42894 12.5714 8.57994 12.5714 9.99977Z"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
Dashboard
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
tone="neutral"
|
||||
size="sm"
|
||||
onClick={() => onDetails(site)}
|
||||
startIcon={<FileIcon className="w-4 h-4" />}
|
||||
>
|
||||
Content
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="md"
|
||||
onClick={() => onDetails(site)}
|
||||
title="View Site Details - See all information about this website"
|
||||
className="shadow-theme-xs inline-flex h-11 items-center justify-center rounded-lg border border-gray-300 px-4 py-3 text-sm font-medium text-gray-700 dark:border-gray-700 dark:text-gray-400"
|
||||
tone="neutral"
|
||||
size="sm"
|
||||
onClick={() => onSettings(site)}
|
||||
startIcon={<SettingsIcon className="w-4 h-4" />}
|
||||
>
|
||||
View Details
|
||||
Settings
|
||||
</Button>
|
||||
</div>
|
||||
<Switch
|
||||
|
||||
@@ -6,13 +6,6 @@
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import Button from '../ui/button/Button';
|
||||
import {
|
||||
ListIcon,
|
||||
GroupIcon,
|
||||
BoltIcon,
|
||||
FileTextIcon,
|
||||
FileIcon,
|
||||
CheckCircleIcon,
|
||||
PaperPlaneIcon,
|
||||
HelpCircleIcon,
|
||||
} from '../../icons';
|
||||
|
||||
@@ -34,75 +27,75 @@ interface QuickActionsWidgetProps {
|
||||
const workflowSteps = [
|
||||
{
|
||||
num: 1,
|
||||
icon: ListIcon,
|
||||
title: 'Add Keywords',
|
||||
description: 'Import your target keywords manually or from CSV',
|
||||
href: '/planner/keyword-opportunities',
|
||||
actionLabel: 'Add',
|
||||
gradient: 'from-brand-500 to-brand-600',
|
||||
buttonTone: 'brand' as const,
|
||||
},
|
||||
{
|
||||
num: 2,
|
||||
icon: GroupIcon,
|
||||
title: 'Auto Cluster',
|
||||
description: 'AI groups related keywords into content clusters',
|
||||
href: '/planner/clusters',
|
||||
href: '/planner/keyword-opportunities', // Clustering runs from keywords page
|
||||
actionLabel: 'Cluster',
|
||||
gradient: 'from-purple-500 to-purple-600',
|
||||
buttonTone: 'brand' as const,
|
||||
},
|
||||
{
|
||||
num: 3,
|
||||
icon: BoltIcon,
|
||||
title: 'Generate Ideas',
|
||||
description: 'Create content ideas from your keyword clusters',
|
||||
href: '/planner/ideas',
|
||||
actionLabel: 'Ideas',
|
||||
gradient: 'from-warning-500 to-warning-600',
|
||||
buttonTone: 'warning' as const,
|
||||
},
|
||||
{
|
||||
num: 4,
|
||||
icon: CheckCircleIcon,
|
||||
title: 'Create Tasks',
|
||||
description: 'Convert approved ideas into content tasks',
|
||||
href: '/writer/tasks',
|
||||
actionLabel: 'Tasks',
|
||||
gradient: 'from-brand-500 to-brand-600',
|
||||
buttonTone: 'brand' as const,
|
||||
},
|
||||
{
|
||||
num: 5,
|
||||
icon: FileTextIcon,
|
||||
title: 'Generate Content',
|
||||
description: 'AI writes SEO-optimized articles from tasks',
|
||||
href: '/writer/content',
|
||||
actionLabel: 'Write',
|
||||
gradient: 'from-success-500 to-success-600',
|
||||
buttonTone: 'success' as const,
|
||||
},
|
||||
{
|
||||
num: 6,
|
||||
icon: FileIcon,
|
||||
title: 'Generate Images',
|
||||
description: 'Create featured images and media for articles',
|
||||
href: '/writer/images',
|
||||
actionLabel: 'Images',
|
||||
gradient: 'from-purple-500 to-purple-600',
|
||||
buttonTone: 'brand' as const,
|
||||
},
|
||||
{
|
||||
num: 7,
|
||||
icon: CheckCircleIcon,
|
||||
title: 'Review & Approve',
|
||||
description: 'Quality check and approve generated content',
|
||||
href: '/writer/review',
|
||||
actionLabel: 'Review',
|
||||
gradient: 'from-warning-500 to-warning-600',
|
||||
buttonTone: 'warning' as const,
|
||||
},
|
||||
{
|
||||
num: 8,
|
||||
icon: PaperPlaneIcon,
|
||||
title: 'Publish to WP',
|
||||
description: 'Push approved content to your WordPress site',
|
||||
href: '/writer/published',
|
||||
actionLabel: 'Publish',
|
||||
gradient: 'from-success-500 to-success-600',
|
||||
buttonTone: 'success' as const,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -132,7 +125,6 @@ export default function QuickActionsWidget({ onAddKeywords }: QuickActionsWidget
|
||||
{/* Column 1: Steps 1-3 */}
|
||||
<div className="space-y-2.5">
|
||||
{workflowSteps.slice(0, 3).map((step) => {
|
||||
const Icon = step.icon;
|
||||
return (
|
||||
<div
|
||||
key={step.num}
|
||||
@@ -143,11 +135,6 @@ export default function QuickActionsWidget({ onAddKeywords }: QuickActionsWidget
|
||||
{step.num}
|
||||
</span>
|
||||
|
||||
{/* Icon with solid gradient background */}
|
||||
<div className={`flex-shrink-0 p-1.5 rounded-lg bg-gradient-to-br ${step.gradient} shadow-sm`}>
|
||||
<Icon className="w-4 h-4 text-white" />
|
||||
</div>
|
||||
|
||||
{/* Text Content */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
@@ -158,13 +145,13 @@ export default function QuickActionsWidget({ onAddKeywords }: QuickActionsWidget
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Action Button */}
|
||||
{/* Action Button - matches step number color */}
|
||||
<Button
|
||||
size="xs"
|
||||
variant="outline"
|
||||
tone="brand"
|
||||
variant="primary"
|
||||
tone={step.buttonTone}
|
||||
onClick={() => navigate(step.href)}
|
||||
className="flex-shrink-0 opacity-70 group-hover:opacity-100 transition-opacity"
|
||||
className="flex-shrink-0"
|
||||
>
|
||||
{step.actionLabel}
|
||||
</Button>
|
||||
@@ -176,7 +163,6 @@ export default function QuickActionsWidget({ onAddKeywords }: QuickActionsWidget
|
||||
{/* Column 2: Steps 4-6 */}
|
||||
<div className="space-y-2.5">
|
||||
{workflowSteps.slice(3, 6).map((step) => {
|
||||
const Icon = step.icon;
|
||||
return (
|
||||
<div
|
||||
key={step.num}
|
||||
@@ -187,11 +173,6 @@ export default function QuickActionsWidget({ onAddKeywords }: QuickActionsWidget
|
||||
{step.num}
|
||||
</span>
|
||||
|
||||
{/* Icon with solid gradient background */}
|
||||
<div className={`flex-shrink-0 p-1.5 rounded-lg bg-gradient-to-br ${step.gradient} shadow-sm`}>
|
||||
<Icon className="w-4 h-4 text-white" />
|
||||
</div>
|
||||
|
||||
{/* Text Content */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
@@ -202,13 +183,13 @@ export default function QuickActionsWidget({ onAddKeywords }: QuickActionsWidget
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Action Button */}
|
||||
{/* Action Button - matches step number color */}
|
||||
<Button
|
||||
size="xs"
|
||||
variant="outline"
|
||||
tone="brand"
|
||||
variant="primary"
|
||||
tone={step.buttonTone}
|
||||
onClick={() => navigate(step.href)}
|
||||
className="flex-shrink-0 opacity-70 group-hover:opacity-100 transition-opacity"
|
||||
className="flex-shrink-0"
|
||||
>
|
||||
{step.actionLabel}
|
||||
</Button>
|
||||
@@ -220,7 +201,6 @@ export default function QuickActionsWidget({ onAddKeywords }: QuickActionsWidget
|
||||
{/* Column 3: Steps 7-8 */}
|
||||
<div className="space-y-2.5">
|
||||
{workflowSteps.slice(6, 8).map((step) => {
|
||||
const Icon = step.icon;
|
||||
return (
|
||||
<div
|
||||
key={step.num}
|
||||
@@ -231,11 +211,6 @@ export default function QuickActionsWidget({ onAddKeywords }: QuickActionsWidget
|
||||
{step.num}
|
||||
</span>
|
||||
|
||||
{/* Icon with solid gradient background */}
|
||||
<div className={`flex-shrink-0 p-1.5 rounded-lg bg-gradient-to-br ${step.gradient} shadow-sm`}>
|
||||
<Icon className="w-4 h-4 text-white" />
|
||||
</div>
|
||||
|
||||
{/* Text Content */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
@@ -246,13 +221,13 @@ export default function QuickActionsWidget({ onAddKeywords }: QuickActionsWidget
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Action Button */}
|
||||
{/* Action Button - matches step number color */}
|
||||
<Button
|
||||
size="xs"
|
||||
variant="outline"
|
||||
tone="brand"
|
||||
variant="primary"
|
||||
tone={step.buttonTone}
|
||||
onClick={() => navigate(step.href)}
|
||||
className="flex-shrink-0 opacity-70 group-hover:opacity-100 transition-opacity"
|
||||
className="flex-shrink-0"
|
||||
>
|
||||
{step.actionLabel}
|
||||
</Button>
|
||||
|
||||
@@ -27,9 +27,7 @@ export default function DemographicCard() {
|
||||
</p>
|
||||
</div>
|
||||
<div className="relative inline-block">
|
||||
<IconButton variant="ghost" size="sm" onClick={toggleDropdown} aria-label="More options">
|
||||
<MoreDotIcon className="text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 size-6" />
|
||||
</IconButton>
|
||||
<IconButton variant="ghost" size="sm" onClick={toggleDropdown} aria-label="More options" icon={<MoreDotIcon className="text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 size-6" />} />
|
||||
<Dropdown
|
||||
isOpen={isOpen}
|
||||
onClose={closeDropdown}
|
||||
|
||||
@@ -108,9 +108,7 @@ export default function MonthlySalesChart() {
|
||||
Monthly Sales
|
||||
</h3>
|
||||
<div className="relative inline-block">
|
||||
<IconButton variant="ghost" size="sm" onClick={toggleDropdown} aria-label="More options">
|
||||
<MoreDotIcon className="text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 size-6" />
|
||||
</IconButton>
|
||||
<IconButton variant="ghost" size="sm" onClick={toggleDropdown} aria-label="More options" icon={<MoreDotIcon className="text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 size-6" />} />
|
||||
<Dropdown
|
||||
isOpen={isOpen}
|
||||
onClose={closeDropdown}
|
||||
|
||||
@@ -77,9 +77,7 @@ export default function MonthlyTarget() {
|
||||
</p>
|
||||
</div>
|
||||
<div className="relative inline-block">
|
||||
<IconButton variant="ghost" size="sm" onClick={toggleDropdown} aria-label="More options">
|
||||
<MoreDotIcon className="text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 size-6" />
|
||||
</IconButton>
|
||||
<IconButton variant="ghost" size="sm" onClick={toggleDropdown} aria-label="More options" icon={<MoreDotIcon className="text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 size-6" />} />
|
||||
<Dropdown
|
||||
isOpen={isOpen}
|
||||
onClose={closeDropdown}
|
||||
|
||||
@@ -19,15 +19,15 @@ const Checkbox: React.FC<CheckboxProps> = ({
|
||||
}) => {
|
||||
return (
|
||||
<label
|
||||
className={`flex items-center space-x-3 group cursor-pointer ${
|
||||
className={`flex items-center gap-2.5 group cursor-pointer ${
|
||||
disabled ? "cursor-not-allowed opacity-60" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="relative w-4 h-4">
|
||||
<div className="relative flex items-center justify-center w-5 h-5">
|
||||
<input
|
||||
id={id}
|
||||
type="checkbox"
|
||||
className={`w-4 h-4 appearance-none cursor-pointer dark:border-gray-700 border border-gray-300 checked:border-transparent rounded-md checked:bg-brand-500 disabled:opacity-60
|
||||
className={`w-5 h-5 appearance-none cursor-pointer dark:border-gray-700 border border-gray-300 checked:border-transparent rounded-md checked:bg-brand-500 disabled:opacity-60
|
||||
${className}`}
|
||||
checked={checked}
|
||||
onChange={(e) => onChange(e.target.checked)}
|
||||
@@ -35,35 +35,31 @@ const Checkbox: React.FC<CheckboxProps> = ({
|
||||
/>
|
||||
{checked && (
|
||||
<svg
|
||||
className="absolute transform -translate-x-1/2 -translate-y-1/2 pointer-events-none top-1/2 left-1/2"
|
||||
className="absolute w-3 h-3 pointer-events-none text-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M11.6666 3.5L5.24992 9.91667L2.33325 7"
|
||||
stroke="white"
|
||||
strokeWidth="1.94437"
|
||||
d="M10 3L4.5 8.5L2 6"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
{disabled && (
|
||||
{disabled && !checked && (
|
||||
<svg
|
||||
className="absolute transform -translate-x-1/2 -translate-y-1/2 pointer-events-none top-1/2 left-1/2"
|
||||
className="absolute w-3 h-3 pointer-events-none text-gray-300"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M11.6666 3.5L5.24992 9.91667L2.33325 7"
|
||||
stroke="#E4E7EC"
|
||||
strokeWidth="2.33333"
|
||||
d="M10 3L4.5 8.5L2 6"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
|
||||
@@ -128,13 +128,30 @@ export default function NotificationDropdown() {
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<IconButton
|
||||
ref={buttonRef as React.RefObject<HTMLButtonElement>}
|
||||
variant="outline"
|
||||
className="relative dropdown-toggle h-11 w-11"
|
||||
onClick={handleClick}
|
||||
aria-label={`Notifications ${unreadCount > 0 ? `(${unreadCount} unread)` : ''}`}
|
||||
>
|
||||
<div className="relative">
|
||||
<IconButton
|
||||
ref={buttonRef as React.RefObject<HTMLButtonElement>}
|
||||
variant="outline"
|
||||
tone="neutral"
|
||||
size="md"
|
||||
icon={
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M10.75 2.29248C10.75 1.87827 10.4143 1.54248 10 1.54248C9.58583 1.54248 9.25004 1.87827 9.25004 2.29248V2.83613C6.08266 3.20733 3.62504 5.9004 3.62504 9.16748V14.4591H3.33337C2.91916 14.4591 2.58337 14.7949 2.58337 15.2091C2.58337 15.6234 2.91916 15.9591 3.33337 15.9591H4.37504H15.625H16.6667C17.0809 15.9591 17.4167 15.6234 17.4167 15.2091C17.4167 14.7949 17.0809 14.4591 16.6667 14.4591H16.375V9.16748C16.375 5.9004 13.9174 3.20733 10.75 2.83613V2.29248ZM14.875 14.4591V9.16748C14.875 6.47509 12.6924 4.29248 10 4.29248C7.30765 4.29248 5.12504 6.47509 5.12504 9.16748V14.4591H14.875ZM8.00004 17.7085C8.00004 18.1228 8.33583 18.4585 8.75004 18.4585H11.25C11.6643 18.4585 12 18.1228 12 17.7085C12 17.2943 11.6643 16.9585 11.25 16.9585H8.75004C8.33583 16.9585 8.00004 17.2943 8.00004 17.7085Z"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
onClick={handleClick}
|
||||
aria-label={`Notifications ${unreadCount > 0 ? `(${unreadCount} unread)` : ''}`}
|
||||
/>
|
||||
{/* Notification badge */}
|
||||
{unreadCount > 0 && (
|
||||
<span className="absolute -right-0.5 -top-0.5 z-10 flex h-5 w-5 items-center justify-center rounded-full bg-warning-500 text-[10px] font-semibold text-white">
|
||||
@@ -142,21 +159,7 @@ export default function NotificationDropdown() {
|
||||
<span className="absolute inline-flex w-full h-full bg-warning-400 rounded-full opacity-75 animate-ping"></span>
|
||||
</span>
|
||||
)}
|
||||
<svg
|
||||
className="fill-current"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M10.75 2.29248C10.75 1.87827 10.4143 1.54248 10 1.54248C9.58583 1.54248 9.25004 1.87827 9.25004 2.29248V2.83613C6.08266 3.20733 3.62504 5.9004 3.62504 9.16748V14.4591H3.33337C2.91916 14.4591 2.58337 14.7949 2.58337 15.2091C2.58337 15.6234 2.91916 15.9591 3.33337 15.9591H4.37504H15.625H16.6667C17.0809 15.9591 17.4167 15.6234 17.4167 15.2091C17.4167 14.7949 17.0809 14.4591 16.6667 14.4591H16.375V9.16748C16.375 5.9004 13.9174 3.20733 10.75 2.83613V2.29248ZM14.875 14.4591V9.16748C14.875 6.47509 12.6924 4.29248 10 4.29248C7.30765 4.29248 5.12504 6.47509 5.12504 9.16748V14.4591H14.875ZM8.00004 17.7085C8.00004 18.1228 8.33583 18.4585 8.75004 18.4585H11.25C11.6643 18.4585 12 18.1228 12 17.7085C12 17.2943 11.6643 16.9585 11.25 16.9585H8.75004C8.33583 16.9585 8.00004 17.2943 8.00004 17.7085Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
<Dropdown
|
||||
isOpen={isOpen}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useState, useRef } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { DropdownItem } from "../ui/dropdown/DropdownItem";
|
||||
import { Dropdown } from "../ui/dropdown/Dropdown";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useAuthStore } from "../../store/authStore";
|
||||
import Button from "../ui/button/Button";
|
||||
|
||||
@@ -26,33 +25,28 @@ export default function UserDropdown() {
|
||||
closeDropdown();
|
||||
};
|
||||
return (
|
||||
<div className="relative">
|
||||
<Button
|
||||
<div className="relative flex-shrink-0">
|
||||
<button
|
||||
ref={buttonRef}
|
||||
onClick={toggleDropdown}
|
||||
variant="ghost"
|
||||
tone="neutral"
|
||||
className="flex items-center text-gray-700 dropdown-toggle dark:text-gray-400"
|
||||
className="flex items-center gap-2 px-2 py-1.5 rounded-lg text-gray-700 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
<span className="mr-3 overflow-hidden rounded-full h-11 w-11 bg-brand-500 flex items-center justify-center">
|
||||
<span className="overflow-hidden rounded-full h-9 w-9 bg-brand-500 flex items-center justify-center flex-shrink-0">
|
||||
{user?.email ? (
|
||||
<span className="text-white font-semibold text-sm">
|
||||
{user.email.charAt(0).toUpperCase()}
|
||||
</span>
|
||||
) : (
|
||||
<img src="/images/user/owner.jpg" alt="User" />
|
||||
<img src="/images/user/owner.jpg" alt="User" className="h-full w-full object-cover" />
|
||||
)}
|
||||
</span>
|
||||
|
||||
<span className="block mr-1 font-medium text-theme-sm">
|
||||
<span className="font-medium text-sm whitespace-nowrap">
|
||||
{user?.username || user?.email?.split("@")[0] || "User"}
|
||||
</span>
|
||||
<svg
|
||||
className={`stroke-gray-500 dark:stroke-gray-400 transition-transform duration-200 ${
|
||||
className={`w-4 h-4 text-gray-500 dark:text-gray-400 transition-transform duration-200 flex-shrink-0 ${
|
||||
isOpen ? "rotate-180" : ""
|
||||
}`}
|
||||
width="18"
|
||||
height="20"
|
||||
viewBox="0 0 18 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -65,7 +59,7 @@ export default function UserDropdown() {
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</Button>
|
||||
</button>
|
||||
|
||||
<Dropdown
|
||||
isOpen={isOpen}
|
||||
|
||||
@@ -301,8 +301,8 @@ export default function SiteIntegrationsSection({ siteId }: SiteIntegrationsSect
|
||||
size="sm"
|
||||
onClick={() => handleSync(integration)}
|
||||
className="flex-1"
|
||||
startIcon={<RefreshCwIcon className="w-4 h-4" />}
|
||||
>
|
||||
<RefreshCwIcon className="w-4 h-4 mr-1" />
|
||||
Sync
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -7,6 +7,7 @@ import React, { useState, useCallback, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Card } from '../ui/card';
|
||||
import Button from '../ui/button/Button';
|
||||
import IconButton from '../ui/button/IconButton';
|
||||
import {
|
||||
ArrowRightIcon,
|
||||
ArrowLeftIcon,
|
||||
@@ -209,14 +210,13 @@ export default function OnboardingWizard({ onComplete, onSkip }: OnboardingWizar
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
<IconButton
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleSkipAll}
|
||||
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
|
||||
>
|
||||
<CloseIcon className="w-5 h-5" />
|
||||
</Button>
|
||||
icon={<CloseIcon className="w-5 h-5" />}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Progress Bar */}
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
CopyIcon,
|
||||
CheckCircleIcon,
|
||||
TimeIcon,
|
||||
ArrowUpIcon,
|
||||
DownloadIcon,
|
||||
} from '../../../icons';
|
||||
import { integrationApi } from '../../../services/integration.api';
|
||||
import { useToast } from '../../ui/toast/ToastContainer';
|
||||
@@ -115,8 +115,12 @@ export default function Step3ConnectIntegration({
|
||||
title: 'Download the Plugin',
|
||||
description: 'Get the IGNY8 Bridge plugin from our dashboard',
|
||||
action: (
|
||||
<Button variant="outline" size="sm" className="gap-1">
|
||||
<ArrowUpIcon className="w-3 h-3" />
|
||||
<Button
|
||||
variant="outline"
|
||||
tone="brand"
|
||||
size="sm"
|
||||
startIcon={<DownloadIcon className="w-3 h-3" />}
|
||||
>
|
||||
Download Plugin
|
||||
</Button>
|
||||
),
|
||||
@@ -174,9 +178,9 @@ export default function Step3ConnectIntegration({
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleCopyApiKey}
|
||||
className="gap-1 flex-shrink-0"
|
||||
className="flex-shrink-0"
|
||||
startIcon={<CopyIcon className="w-4 h-4" />}
|
||||
>
|
||||
<CopyIcon className="w-4 h-4" />
|
||||
Copy
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -167,13 +167,12 @@ export default function Step4AddKeywords({
|
||||
className="pl-10"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
<IconButton
|
||||
variant="outline"
|
||||
onClick={handleAddKeyword}
|
||||
disabled={!inputValue.trim()}
|
||||
>
|
||||
<PlusIcon className="w-4 h-4" />
|
||||
</Button>
|
||||
icon={<PlusIcon className="w-4 h-4" />}
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
Tip: Paste a comma-separated list or one keyword per line
|
||||
|
||||
@@ -118,9 +118,8 @@ export default function PublishingRules({ rules, onChange }: PublishingRulesProp
|
||||
Example: Publish blog posts to WordPress but guides to your main site
|
||||
</p>
|
||||
</div>
|
||||
<Button onClick={handleAddRule} variant="primary" size="sm">
|
||||
<PlusIcon className="w-4 h-4 mr-2" />
|
||||
+ Add a Publishing Rule
|
||||
<Button onClick={handleAddRule} variant="primary" size="sm" startIcon={<PlusIcon className="w-4 h-4" />}>
|
||||
Add a Publishing Rule
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import React, { useState } from 'react';
|
||||
import { EyeIcon, XIcon, Maximize2Icon } from '../../icons';
|
||||
import { Card } from '../../ui/card';
|
||||
import Button from '../../ui/button/Button';
|
||||
import IconButton from '../../ui/button/IconButton';
|
||||
|
||||
export interface LayoutPreviewProps {
|
||||
layoutId: string;
|
||||
@@ -145,15 +146,12 @@ export default function LayoutPreview({ layoutId, layoutName, onClose, onSelect
|
||||
{isFullscreen ? 'Exit' : 'Fullscreen'}
|
||||
</Button>
|
||||
{onSelect && (
|
||||
<Button variant="primary" size="sm" onClick={onSelect}>
|
||||
<EyeIcon className="w-4 h-4 mr-2" />
|
||||
<Button variant="primary" size="sm" onClick={onSelect} startIcon={<EyeIcon className="w-4 h-4" />}>
|
||||
Select Layout
|
||||
</Button>
|
||||
)}
|
||||
{onClose && (
|
||||
<Button variant="ghost" size="sm" onClick={onClose}>
|
||||
<XIcon className="w-4 h-4" />
|
||||
</Button>
|
||||
<IconButton variant="ghost" size="sm" onClick={onClose} icon={<XIcon className="w-4 h-4" />} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,9 +9,10 @@ import Badge from '../ui/badge/Badge';
|
||||
interface SiteTypeBadgeProps {
|
||||
hostingType: string;
|
||||
className?: string;
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
}
|
||||
|
||||
export default function SiteTypeBadge({ hostingType, className = '' }: SiteTypeBadgeProps) {
|
||||
export default function SiteTypeBadge({ hostingType, className = '', size = 'sm' }: SiteTypeBadgeProps) {
|
||||
const getTypeInfo = () => {
|
||||
switch (hostingType) {
|
||||
case 'igny8_sites':
|
||||
@@ -41,11 +42,11 @@ export default function SiteTypeBadge({ hostingType, className = '' }: SiteTypeB
|
||||
<Badge
|
||||
variant="soft"
|
||||
color={typeInfo.color}
|
||||
size={size}
|
||||
startIcon={typeInfo.icon}
|
||||
className={className}
|
||||
>
|
||||
{typeInfo.label}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -90,14 +90,12 @@ export default function StyleEditor({ styleSettings, onChange, onSave, onReset }
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{onReset && (
|
||||
<Button variant="outline" onClick={onReset}>
|
||||
<RefreshCwIcon className="w-4 h-4 mr-2" />
|
||||
<Button variant="outline" onClick={onReset} startIcon={<RefreshCwIcon className="w-4 h-4" />}>
|
||||
Reset
|
||||
</Button>
|
||||
)}
|
||||
{onSave && (
|
||||
<Button variant="primary" onClick={onSave}>
|
||||
<SaveIcon className="w-4 h-4 mr-2" />
|
||||
<Button variant="primary" onClick={onSave} startIcon={<SaveIcon className="w-4 h-4" />}>
|
||||
Save Styles
|
||||
</Button>
|
||||
)}
|
||||
@@ -112,8 +110,8 @@ export default function StyleEditor({ styleSettings, onChange, onSave, onReset }
|
||||
tone="brand"
|
||||
size="sm"
|
||||
onClick={() => setActiveTab('css')}
|
||||
startIcon={<CodeIcon className="w-4 h-4" />}
|
||||
>
|
||||
<CodeIcon className="w-4 h-4 mr-2" />
|
||||
Custom CSS
|
||||
</Button>
|
||||
<Button
|
||||
@@ -121,8 +119,8 @@ export default function StyleEditor({ styleSettings, onChange, onSave, onReset }
|
||||
tone="brand"
|
||||
size="sm"
|
||||
onClick={() => setActiveTab('colors')}
|
||||
startIcon={<PaletteIcon className="w-4 h-4" />}
|
||||
>
|
||||
<PaletteIcon className="w-4 h-4 mr-2" />
|
||||
Colors
|
||||
</Button>
|
||||
<Button
|
||||
@@ -130,8 +128,8 @@ export default function StyleEditor({ styleSettings, onChange, onSave, onReset }
|
||||
tone="brand"
|
||||
size="sm"
|
||||
onClick={() => setActiveTab('typography')}
|
||||
startIcon={<TypeIcon className="w-4 h-4" />}
|
||||
>
|
||||
<TypeIcon className="w-4 h-4 mr-2" />
|
||||
Typography
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -74,8 +74,8 @@ export default function TemplateCustomizer({
|
||||
tone="brand"
|
||||
size="sm"
|
||||
onClick={() => setActiveTab('layout')}
|
||||
startIcon={<LayoutIcon className="w-4 h-4" />}
|
||||
>
|
||||
<LayoutIcon className="w-4 h-4 mr-2" />
|
||||
Layout
|
||||
</Button>
|
||||
<Button
|
||||
@@ -83,8 +83,8 @@ export default function TemplateCustomizer({
|
||||
tone="brand"
|
||||
size="sm"
|
||||
onClick={() => setActiveTab('colors')}
|
||||
startIcon={<PaletteIcon className="w-4 h-4" />}
|
||||
>
|
||||
<PaletteIcon className="w-4 h-4 mr-2" />
|
||||
Colors
|
||||
</Button>
|
||||
<Button
|
||||
@@ -92,8 +92,8 @@ export default function TemplateCustomizer({
|
||||
tone="brand"
|
||||
size="sm"
|
||||
onClick={() => setActiveTab('typography')}
|
||||
startIcon={<TypeIcon className="w-4 h-4" />}
|
||||
>
|
||||
<TypeIcon className="w-4 h-4 mr-2" />
|
||||
Typography
|
||||
</Button>
|
||||
<Button
|
||||
@@ -101,8 +101,8 @@ export default function TemplateCustomizer({
|
||||
tone="brand"
|
||||
size="sm"
|
||||
onClick={() => setActiveTab('spacing')}
|
||||
startIcon={<SettingsIcon className="w-4 h-4" />}
|
||||
>
|
||||
<SettingsIcon className="w-4 h-4 mr-2" />
|
||||
Spacing
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useNavigate } from 'react-router-dom';
|
||||
import { GlobeIcon, CheckCircleIcon, XCircleIcon, SettingsIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon } from '../../icons';
|
||||
import { Card } from '../ui/card';
|
||||
import Button from '../ui/button/Button';
|
||||
import IconButton from '../ui/button/IconButton';
|
||||
import Badge from '../ui/badge/Badge';
|
||||
|
||||
interface WordPressIntegration {
|
||||
@@ -175,8 +176,8 @@ export default function WordPressIntegrationCard({
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex-1"
|
||||
startIcon={<SettingsIcon className="w-4 h-4" />}
|
||||
>
|
||||
<SettingsIcon className="w-4 h-4 mr-2" />
|
||||
Manage
|
||||
</Button>
|
||||
{siteId && (
|
||||
@@ -190,14 +191,13 @@ export default function WordPressIntegrationCard({
|
||||
</Button>
|
||||
)}
|
||||
{onSync && (
|
||||
<Button
|
||||
<IconButton
|
||||
onClick={onSync}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={loading}
|
||||
>
|
||||
<RefreshCwIcon className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />
|
||||
</Button>
|
||||
icon={<RefreshCwIcon className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -286,16 +286,14 @@ export default function WordPressIntegrationForm({
|
||||
type={apiKeyVisible ? 'text' : 'password'}
|
||||
value={apiKeyVisible ? apiKey : maskApiKey(apiKey)}
|
||||
/>
|
||||
<Button
|
||||
<IconButton
|
||||
onClick={handleCopyApiKey}
|
||||
variant="outline"
|
||||
tone="neutral"
|
||||
size="sm"
|
||||
className="absolute top-1/2 right-0 -translate-y-1/2 rounded-l-none"
|
||||
>
|
||||
<CopyIcon className="w-4 h-4" />
|
||||
Copy
|
||||
</Button>
|
||||
icon={<CopyIcon className="w-4 h-4" />}
|
||||
/>
|
||||
</div>
|
||||
<div className="group relative inline-block">
|
||||
<IconButton
|
||||
@@ -303,9 +301,8 @@ export default function WordPressIntegrationForm({
|
||||
disabled={generatingKey}
|
||||
variant="outline"
|
||||
title="Regenerate"
|
||||
>
|
||||
<RefreshCwIcon className={`w-5 h-5 ${generatingKey ? 'animate-spin' : ''}`} />
|
||||
</IconButton>
|
||||
icon={<RefreshCwIcon className={`w-5 h-5 ${generatingKey ? 'animate-spin' : ''}`} />}
|
||||
/>
|
||||
<div className="invisible absolute bottom-full left-1/2 z-50 mb-2.5 -translate-x-1/2 opacity-0 transition-opacity duration-300 group-hover:visible group-hover:opacity-100">
|
||||
<div className="relative">
|
||||
<div className="rounded-lg bg-white px-3 py-2 text-xs font-medium whitespace-nowrap text-gray-700 shadow-xs dark:bg-gray-800 dark:text-white">
|
||||
@@ -348,18 +345,16 @@ export default function WordPressIntegrationForm({
|
||||
disabled={generatingKey}
|
||||
variant="ghost"
|
||||
title="Regenerate API key"
|
||||
>
|
||||
<RefreshCwIcon className={`w-5 h-5 ${generatingKey ? 'animate-spin' : ''}`} />
|
||||
</IconButton>
|
||||
icon={<RefreshCwIcon className={`w-5 h-5 ${generatingKey ? 'animate-spin' : ''}`} />}
|
||||
/>
|
||||
<IconButton
|
||||
onClick={handleRevokeApiKey}
|
||||
disabled={generatingKey}
|
||||
variant="ghost"
|
||||
tone="danger"
|
||||
title="Revoke API key"
|
||||
>
|
||||
<TrashBinIcon className="w-5 h-5" />
|
||||
</IconButton>
|
||||
icon={<TrashBinIcon className="w-5 h-5" />}
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -389,8 +384,8 @@ export default function WordPressIntegrationForm({
|
||||
<Button
|
||||
onClick={handleDownloadPlugin}
|
||||
variant="solid"
|
||||
startIcon={<DownloadIcon className="w-4 h-4" />}
|
||||
>
|
||||
<DownloadIcon className="w-4 h-4 mr-2" />
|
||||
Download Plugin
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -24,6 +24,7 @@ interface ButtonGroupItemProps {
|
||||
isActive?: boolean;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
startIcon?: ReactNode;
|
||||
}
|
||||
|
||||
export const ButtonGroupItem: React.FC<ButtonGroupItemProps> = ({
|
||||
@@ -32,18 +33,20 @@ export const ButtonGroupItem: React.FC<ButtonGroupItemProps> = ({
|
||||
isActive = false,
|
||||
className = "",
|
||||
disabled = false,
|
||||
startIcon,
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
className={`px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-white disabled:opacity-50 disabled:cursor-not-allowed ${
|
||||
className={`inline-flex items-center gap-1.5 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-white disabled:opacity-50 disabled:cursor-not-allowed ${
|
||||
isActive
|
||||
? "bg-gray-100 text-gray-900 dark:bg-white/10 dark:text-white"
|
||||
: ""
|
||||
} ${className}`}
|
||||
type="button"
|
||||
>
|
||||
{startIcon}
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
|
||||
@@ -51,7 +51,7 @@ export const Modal: React.FC<ModalProps> = ({
|
||||
|
||||
const contentClasses = isFullscreen
|
||||
? "w-full h-full"
|
||||
: "relative w-full rounded-3xl bg-white dark:bg-gray-900";
|
||||
: "relative w-full max-w-lg mx-4 rounded-3xl bg-white dark:bg-gray-900 shadow-xl";
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 flex items-center justify-center overflow-y-auto modal z-99999">
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
<svg
|
||||
class="fill-current"
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M5.31462 10.3761C5.45194 10.5293 5.65136 10.6257 5.87329 10.6257C5.8736 10.6257 5.8739 10.6257 5.87421 10.6257C6.0663 10.6259 6.25845 10.5527 6.40505 10.4062L9.40514 7.4082C9.69814 7.11541 9.69831 6.64054 9.40552 6.34754C9.11273 6.05454 8.63785 6.05438 8.34486 6.34717L6.62329 8.06753L6.62329 1.875C6.62329 1.46079 6.28751 1.125 5.87329 1.125C5.45908 1.125 5.12329 1.46079 5.12329 1.875L5.12329 8.06422L3.40516 6.34719C3.11218 6.05439 2.6373 6.05454 2.3445 6.34752C2.0517 6.64051 2.05185 7.11538 2.34484 7.40818L5.31462 10.3761Z"
|
||||
fill=""
|
||||
/>
|
||||
</svg>
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M5.31462 10.3761C5.45194 10.5293 5.65136 10.6257 5.87329 10.6257C5.8736 10.6257 5.8739 10.6257 5.87421 10.6257C6.0663 10.6259 6.25845 10.5527 6.40505 10.4062L9.40514 7.4082C9.69814 7.11541 9.69831 6.64054 9.40552 6.34754C9.11273 6.05454 8.63785 6.05438 8.34486 6.34717L6.62329 8.06753L6.62329 1.875C6.62329 1.46079 6.28751 1.125 5.87329 1.125C5.45908 1.125 5.12329 1.46079 5.12329 1.875L5.12329 8.06422L3.40516 6.34719C3.11218 6.05439 2.6373 6.05454 2.3445 6.34752C2.0517 6.64051 2.05185 7.11538 2.34484 7.40818L5.31462 10.3761Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 858 B After Width: | Height: | Size: 735 B |
@@ -1,15 +1,14 @@
|
||||
<svg
|
||||
className="fill-current"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M17.4175 9.9986C17.4178 10.1909 17.3446 10.3832 17.198 10.53L12.2013 15.5301C11.9085 15.8231 11.4337 15.8233 11.1407 15.5305C10.8477 15.2377 10.8475 14.7629 11.1403 14.4699L14.8604 10.7472L3.33301 10.7472C2.91879 10.7472 2.58301 10.4114 2.58301 9.99715C2.58301 9.58294 2.91879 9.24715 3.33301 9.24715L14.8549 9.24715L11.1403 5.53016C10.8475 5.23717 10.8477 4.7623 11.1407 4.4695C11.4336 4.1767 11.9085 4.17685 12.2013 4.46984L17.1588 9.43049C17.3173 9.568 17.4175 9.77087 17.4175 9.99715C17.4175 9.99763 17.4175 9.99812 17.4175 9.9986Z"
|
||||
fill=""
|
||||
/>
|
||||
</svg>
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M17.4175 9.9986C17.4178 10.1909 17.3446 10.3832 17.198 10.53L12.2013 15.5301C11.9085 15.8231 11.4337 15.8233 11.1407 15.5305C10.8477 15.2377 10.8475 14.7629 11.1403 14.4699L14.8604 10.7472L3.33301 10.7472C2.91879 10.7472 2.58301 10.4114 2.58301 9.99715C2.58301 9.58294 2.91879 9.24715 3.33301 9.24715L14.8549 9.24715L11.1403 5.53016C10.8475 5.23717 10.8477 4.7623 11.1407 4.4695C11.4336 4.1767 11.9085 4.17685 12.2013 4.46984L17.1588 9.43049C17.3173 9.568 17.4175 9.77087 17.4175 9.99715C17.4175 9.99763 17.4175 9.99812 17.4175 9.9986Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 897 B After Width: | Height: | Size: 742 B |
@@ -1,16 +1,14 @@
|
||||
|
||||
<svg
|
||||
className="fill-current"
|
||||
width="13"
|
||||
height="12"
|
||||
viewBox="0 0 13 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M6.06462 1.62393C6.20193 1.47072 6.40135 1.37432 6.62329 1.37432C6.6236 1.37432 6.62391 1.37432 6.62422 1.37432C6.81631 1.37415 7.00845 1.44731 7.15505 1.5938L10.1551 4.5918C10.4481 4.88459 10.4483 5.35946 10.1555 5.65246C9.86273 5.94546 9.38785 5.94562 9.09486 5.65283L7.37329 3.93247L7.37329 10.125C7.37329 10.5392 7.03751 10.875 6.62329 10.875C6.20908 10.875 5.87329 10.5392 5.87329 10.125L5.87329 3.93578L4.15516 5.65281C3.86218 5.94561 3.3873 5.94546 3.0945 5.65248C2.8017 5.35949 2.80185 4.88462 3.09484 4.59182L6.06462 1.62393Z"
|
||||
fill=""
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
width="13"
|
||||
height="12"
|
||||
viewBox="0 0 13 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M6.06462 1.62393C6.20193 1.47072 6.40135 1.37432 6.62329 1.37432C6.6236 1.37432 6.62391 1.37432 6.62422 1.37432C6.81631 1.37415 7.00845 1.44731 7.15505 1.5938L10.1551 4.5918C10.4481 4.88459 10.4483 5.35946 10.1555 5.65246C9.86273 5.94546 9.38785 5.94562 9.09486 5.65283L7.37329 3.93247L7.37329 10.125C7.37329 10.5392 7.03751 10.875 6.62329 10.875C6.20908 10.875 5.87329 10.5392 5.87329 10.125L5.87329 3.93578L4.15516 5.65281C3.86218 5.94561 3.3873 5.94546 3.0945 5.65248C2.8017 5.35949 2.80185 4.88462 3.09484 4.59182L6.06462 1.62393Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 926 B After Width: | Height: | Size: 741 B |
@@ -1,14 +1,14 @@
|
||||
<svg
|
||||
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M10.0002 13.8619C7.23361 13.8619 4.86803 12.1372 3.92328 9.70241C4.86804 7.26761 7.23361 5.54297 10.0002 5.54297C12.7667 5.54297 15.1323 7.26762 16.0771 9.70243C15.1323 12.1372 12.7667 13.8619 10.0002 13.8619ZM10.0002 4.04297C6.48191 4.04297 3.49489 6.30917 2.4155 9.4593C2.3615 9.61687 2.3615 9.78794 2.41549 9.94552C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C13.5184 15.3619 16.5055 13.0957 17.5849 9.94555C17.6389 9.78797 17.6389 9.6169 17.5849 9.45932C16.5055 6.30919 13.5184 4.04297 10.0002 4.04297ZM9.99151 7.84413C8.96527 7.84413 8.13333 8.67606 8.13333 9.70231C8.13333 10.7286 8.96527 11.5605 9.99151 11.5605H10.0064C11.0326 11.5605 11.8646 10.7286 11.8646 9.70231C11.8646 8.67606 11.0326 7.84413 10.0064 7.84413H9.99151Z"
|
||||
/>
|
||||
</svg>
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M10.0002 13.8619C7.23361 13.8619 4.86803 12.1372 3.92328 9.70241C4.86804 7.26761 7.23361 5.54297 10.0002 5.54297C12.7667 5.54297 15.1323 7.26762 16.0771 9.70243C15.1323 12.1372 12.7667 13.8619 10.0002 13.8619ZM10.0002 4.04297C6.48191 4.04297 3.49489 6.30917 2.4155 9.4593C2.3615 9.61687 2.3615 9.78794 2.41549 9.94552C3.49488 13.0957 6.48191 15.3619 10.0002 15.3619C13.5184 15.3619 16.5055 13.0957 17.5849 9.94555C17.6389 9.78797 17.6389 9.6169 17.5849 9.45932C16.5055 6.30919 13.5184 4.04297 10.0002 4.04297ZM9.99151 7.84413C8.96527 7.84413 8.13333 8.67606 8.13333 9.70231C8.13333 10.7286 8.96527 11.5605 9.99151 11.5605H10.0064C11.0326 11.5605 11.8646 10.7286 11.8646 9.70231C11.8646 8.67606 11.0326 7.84413 10.0064 7.84413H9.99151Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 941 B |
@@ -55,6 +55,8 @@ import { ReactComponent as MoreDotIcon } from "./moredot.svg?react";
|
||||
import { ReactComponent as AlertHexaIcon } from "./alert-hexa.svg?react";
|
||||
import { ReactComponent as ErrorHexaIcon } from "./info-hexa.svg?react";
|
||||
import { ReactComponent as CalendarIcon } from "./calendar.svg?react";
|
||||
import { ReactComponent as SaveIcon } from "./save.svg?react";
|
||||
import { ReactComponent as UserPlusIcon } from "./user-plus.svg?react";
|
||||
|
||||
export {
|
||||
ErrorHexaIcon,
|
||||
@@ -114,6 +116,8 @@ export {
|
||||
AngleLeftIcon,
|
||||
AngleRightIcon,
|
||||
CalendarIcon,
|
||||
SaveIcon,
|
||||
UserPlusIcon,
|
||||
};
|
||||
|
||||
// Aliases for commonly used icon names (lucide-react replacements)
|
||||
@@ -153,7 +157,6 @@ export { FileIcon as FileArchiveIcon }; // File archive alias
|
||||
export { PageIcon as ExternalLinkIcon }; // External link alias
|
||||
export { PencilIcon as Wand2Icon }; // Wand alias
|
||||
export { BoxCubeIcon as LayoutIcon }; // Layout alias
|
||||
export { PencilIcon as SaveIcon }; // Save alias
|
||||
export { BoxCubeIcon as CodeIcon }; // Code alias
|
||||
export { GridIcon as SearchIcon }; // Search alias
|
||||
export { BoxCubeIcon as PaletteIcon }; // Palette alias
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
<svg
|
||||
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M4.98481 2.44399C3.11333 1.57147 1.15325 3.46979 1.96543 5.36824L3.82086 9.70527C3.90146 9.89367 3.90146 10.1069 3.82086 10.2953L1.96543 14.6323C1.15326 16.5307 3.11332 18.4291 4.98481 17.5565L16.8184 12.0395C18.5508 11.2319 18.5508 8.76865 16.8184 7.961L4.98481 2.44399ZM3.34453 4.77824C3.0738 4.14543 3.72716 3.51266 4.35099 3.80349L16.1846 9.32051C16.762 9.58973 16.762 10.4108 16.1846 10.68L4.35098 16.197C3.72716 16.4879 3.0738 15.8551 3.34453 15.2223L5.19996 10.8853C5.21944 10.8397 5.23735 10.7937 5.2537 10.7473L9.11784 10.7473C9.53206 10.7473 9.86784 10.4115 9.86784 9.99726C9.86784 9.58304 9.53206 9.24726 9.11784 9.24726L5.25157 9.24726C5.2358 9.20287 5.2186 9.15885 5.19996 9.11528L3.34453 4.77824Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M4.98481 2.44399C3.11333 1.57147 1.15325 3.46979 1.96543 5.36824L3.82086 9.70527C3.90146 9.89367 3.90146 10.1069 3.82086 10.2953L1.96543 14.6323C1.15326 16.5307 3.11332 18.4291 4.98481 17.5565L16.8184 12.0395C18.5508 11.2319 18.5508 8.76865 16.8184 7.961L4.98481 2.44399ZM3.34453 4.77824C3.0738 4.14543 3.72716 3.51266 4.35099 3.80349L16.1846 9.32051C16.762 9.58973 16.762 10.4108 16.1846 10.68L4.35098 16.197C3.72716 16.4879 3.0738 15.8551 3.34453 15.2223L5.19996 10.8853C5.21944 10.8397 5.23735 10.7937 5.2537 10.7473L9.11784 10.7473C9.53206 10.7473 9.86784 10.4115 9.86784 9.99726C9.86784 9.58304 9.53206 9.24726 9.11784 9.24726L5.25157 9.24726C5.2358 9.20287 5.2186 9.15885 5.19996 9.11528L3.34453 4.77824Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 917 B |
@@ -1,15 +1,14 @@
|
||||
<svg
|
||||
class="fill-current"
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M5.25012 3C5.25012 2.58579 5.58591 2.25 6.00012 2.25C6.41433 2.25 6.75012 2.58579 6.75012 3V5.25012L9.00034 5.25012C9.41455 5.25012 9.75034 5.58591 9.75034 6.00012C9.75034 6.41433 9.41455 6.75012 9.00034 6.75012H6.75012V9.00034C6.75012 9.41455 6.41433 9.75034 6.00012 9.75034C5.58591 9.75034 5.25012 9.41455 5.25012 9.00034L5.25012 6.75012H3C2.58579 6.75012 2.25 6.41433 2.25 6.00012C2.25 5.58591 2.58579 5.25012 3 5.25012H5.25012V3Z"
|
||||
fill=""
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M5.25012 3C5.25012 2.58579 5.58591 2.25 6.00012 2.25C6.41433 2.25 6.75012 2.58579 6.75012 3V5.25012L9.00034 5.25012C9.41455 5.25012 9.75034 5.58591 9.75034 6.00012C9.75034 6.41433 9.41455 6.75012 9.00034 6.75012H6.75012V9.00034C6.75012 9.41455 6.41433 9.75034 6.00012 9.75034C5.58591 9.75034 5.25012 9.41455 5.25012 9.00034L5.25012 6.75012H3C2.58579 6.75012 2.25 6.41433 2.25 6.00012C2.25 5.58591 2.58579 5.25012 3 5.25012H5.25012V3Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 708 B After Width: | Height: | Size: 640 B |
29
frontend/src/icons/save.svg
Normal file
@@ -0,0 +1,29 @@
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V5C3 4.46957 3.21071 3.96086 3.58579 3.58579C3.96086 3.21071 4.46957 3 5 3H16L21 8V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21Z"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M17 21V13H7V21"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7 3V8H15"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 759 B |
@@ -1,15 +1,14 @@
|
||||
<svg
|
||||
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M3.04175 9.99984C3.04175 6.15686 6.1571 3.0415 10.0001 3.0415C13.8431 3.0415 16.9584 6.15686 16.9584 9.99984C16.9584 13.8428 13.8431 16.9582 10.0001 16.9582C6.1571 16.9582 3.04175 13.8428 3.04175 9.99984ZM10.0001 1.5415C5.32867 1.5415 1.54175 5.32843 1.54175 9.99984C1.54175 14.6712 5.32867 18.4582 10.0001 18.4582C14.6715 18.4582 18.4584 14.6712 18.4584 9.99984C18.4584 5.32843 14.6715 1.5415 10.0001 1.5415ZM9.99998 10.7498C9.58577 10.7498 9.24998 10.4141 9.24998 9.99984V5.4165C9.24998 5.00229 9.58577 4.6665 9.99998 4.6665C10.4142 4.6665 10.75 5.00229 10.75 5.4165V9.24984H13.3334C13.7476 9.24984 14.0834 9.58562 14.0834 9.99984C14.0834 10.4141 13.7476 10.7498 13.3334 10.7498H10.0001H9.99998Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M3.04175 9.99984C3.04175 6.15686 6.1571 3.0415 10.0001 3.0415C13.8431 3.0415 16.9584 6.15686 16.9584 9.99984C16.9584 13.8428 13.8431 16.9582 10.0001 16.9582C6.1571 16.9582 3.04175 13.8428 3.04175 9.99984ZM10.0001 1.5415C5.32867 1.5415 1.54175 5.32843 1.54175 9.99984C1.54175 14.6712 5.32867 18.4582 10.0001 18.4582C14.6715 18.4582 18.4584 14.6712 18.4584 9.99984C18.4584 5.32843 14.6715 1.5415 10.0001 1.5415ZM9.99998 10.7498C9.58577 10.7498 9.24998 10.4141 9.24998 9.99984V5.4165C9.24998 5.00229 9.58577 4.6665 9.99998 4.6665C10.4142 4.6665 10.75 5.00229 10.75 5.4165V9.24984H13.3334C13.7476 9.24984 14.0834 9.58562 14.0834 9.99984C14.0834 10.4141 13.7476 10.7498 13.3334 10.7498H10.0001H9.99998Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 904 B |
36
frontend/src/icons/user-plus.svg
Normal file
@@ -0,0 +1,36 @@
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16 21V19C16 17.9391 15.5786 16.9217 14.8284 16.1716C14.0783 15.4214 13.0609 15 12 15H5C3.93913 15 2.92172 15.4214 2.17157 16.1716C1.42143 16.9217 1 17.9391 1 19V21"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M8.5 11C10.7091 11 12.5 9.20914 12.5 7C12.5 4.79086 10.7091 3 8.5 3C6.29086 3 4.5 4.79086 4.5 7C4.5 9.20914 6.29086 11 8.5 11Z"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M20 8V14"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M23 11H17"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 925 B |
@@ -107,14 +107,17 @@ const AppHeader: React.FC = () => {
|
||||
{/* Mobile Menu Toggle */}
|
||||
<IconButton
|
||||
variant="ghost"
|
||||
tone="neutral"
|
||||
size="md"
|
||||
onClick={toggleApplicationMenu}
|
||||
className="w-10 h-10 z-99999 lg:hidden"
|
||||
className="z-99999 lg:hidden"
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M5.99902 10.4951C6.82745 10.4951 7.49902 11.1667 7.49902 11.9951V12.0051C7.49902 12.8335 6.82745 13.5051 5.99902 13.5051C5.1706 13.5051 4.49902 12.8335 4.49902 12.0051V11.9951C4.49902 11.1667 5.1706 10.4951 5.99902 10.4951ZM17.999 10.4951C18.8275 10.4951 19.499 11.1667 19.499 11.9951V12.0051C19.499 12.8335 18.8275 13.5051 17.999 13.5051C17.1706 13.5051 16.499 12.8335 16.499 12.0051V11.9951C16.499 11.1667 17.1706 10.4951 17.999 10.4951ZM13.499 11.9951C13.499 11.1667 12.8275 10.4951 11.999 10.4951C11.1706 10.4951 10.499 11.1667 10.499 11.9951V12.0051C10.499 12.8335 11.1706 13.5051 11.999 13.5051C12.8275 13.5051 13.499 12.8335 13.499 12.0051V11.9951Z" fill="currentColor" />
|
||||
</svg>
|
||||
</IconButton>
|
||||
icon={
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M5.99902 10.4951C6.82745 10.4951 7.49902 11.1667 7.49902 11.9951V12.0051C7.49902 12.8335 6.82745 13.5051 5.99902 13.5051C5.1706 13.5051 4.49902 12.8335 4.49902 12.0051V11.9951C4.49902 11.1667 5.1706 10.4951 5.99902 10.4951ZM17.999 10.4951C18.8275 10.4951 19.499 11.1667 19.499 11.9951V12.0051C19.499 12.8335 18.8275 13.5051 17.999 13.5051C17.1706 13.5051 16.499 12.8335 16.499 12.0051V11.9951C16.499 11.1667 17.1706 10.4951 17.999 10.4951ZM13.499 11.9951C13.499 11.1667 12.8275 10.4951 11.999 10.4951C11.1706 10.4951 10.499 11.1667 10.499 11.9951V12.0051C10.499 12.8335 11.1706 13.5051 11.999 13.5051C12.8275 13.5051 13.499 12.8335 13.499 12.0051V11.9951Z" fill="currentColor" />
|
||||
</svg>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Page Title with Badge - Desktop */}
|
||||
{pageInfo && (
|
||||
@@ -122,20 +125,22 @@ const AppHeader: React.FC = () => {
|
||||
{/* Sidebar Toggle Button - Always visible on desktop */}
|
||||
<IconButton
|
||||
variant="outline"
|
||||
size="xs"
|
||||
tone="neutral"
|
||||
size="sm"
|
||||
shape="circle"
|
||||
onClick={toggleSidebar}
|
||||
className="w-6 h-6 rounded-full"
|
||||
aria-label={isExpanded ? "Collapse Sidebar" : "Expand Sidebar"}
|
||||
>
|
||||
<svg
|
||||
className={`w-3.5 h-3.5 text-gray-500 dark:text-gray-400 transition-transform duration-300 ${isExpanded ? 'rotate-180' : ''}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</IconButton>
|
||||
icon={
|
||||
<svg
|
||||
className={`w-3.5 h-3.5 transition-transform duration-300 ${isExpanded ? 'rotate-180' : ''}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
}
|
||||
/>
|
||||
|
||||
{pageInfo.badge && (
|
||||
<div className={`flex items-center justify-center w-8 h-8 rounded-lg ${badgeColors[pageInfo.badge.color]?.bg || 'bg-gray-600'} flex-shrink-0`}>
|
||||
@@ -188,15 +193,17 @@ const AppHeader: React.FC = () => {
|
||||
{/* Search Icon */}
|
||||
<IconButton
|
||||
variant="ghost"
|
||||
tone="neutral"
|
||||
size="md"
|
||||
onClick={() => setIsSearchOpen(true)}
|
||||
className="w-10 h-10"
|
||||
title="Search (⌘K)"
|
||||
aria-label="Search"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
</IconButton>
|
||||
icon={
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Dark Mode Toggler */}
|
||||
<ThemeToggleButton />
|
||||
|
||||
@@ -176,18 +176,9 @@ export default function LinkerContentList() {
|
||||
disabled={isProcessing || processing === -1}
|
||||
variant="primary"
|
||||
size="sm"
|
||||
startIcon={isProcessing ? <div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" /> : <PlugInIcon className="w-4 h-4" />}
|
||||
>
|
||||
{isProcessing ? (
|
||||
<>
|
||||
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
||||
Processing...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<PlugInIcon className="w-4 h-4" />
|
||||
Add Links
|
||||
</>
|
||||
)}
|
||||
{isProcessing ? 'Processing...' : 'Add Links'}
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -171,18 +171,9 @@ export default function OptimizerContentSelector() {
|
||||
variant="primary"
|
||||
onClick={handleBatchOptimize}
|
||||
disabled={selectedIds.length === 0 || processing.length > 0}
|
||||
startIcon={processing.length > 0 ? <div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" /> : <BoltIcon className="w-4 h-4" />}
|
||||
>
|
||||
{processing.length > 0 ? (
|
||||
<>
|
||||
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
||||
Optimizing...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<BoltIcon className="w-4 h-4" />
|
||||
Optimize Selected ({selectedIds.length})
|
||||
</>
|
||||
)}
|
||||
{processing.length > 0 ? 'Optimizing...' : `Optimize Selected (${selectedIds.length})`}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -270,18 +261,9 @@ export default function OptimizerContentSelector() {
|
||||
size="sm"
|
||||
onClick={() => handleOptimize(item.id)}
|
||||
disabled={isProcessing || processing.length > 0}
|
||||
startIcon={isProcessing ? <div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" /> : <BoltIcon className="w-4 h-4" />}
|
||||
>
|
||||
{isProcessing ? (
|
||||
<>
|
||||
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
||||
Optimizing...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<BoltIcon className="w-4 h-4" />
|
||||
Optimize
|
||||
</>
|
||||
)}
|
||||
{isProcessing ? 'Optimizing...' : 'Optimize'}
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -157,9 +157,8 @@ export default function ClusterDetail() {
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => navigate('/planner/clusters')}
|
||||
className="flex items-center gap-2"
|
||||
startIcon={<ChevronLeftIcon className="w-4 h-4" />}
|
||||
>
|
||||
<ChevronLeftIcon className="w-4 h-4" />
|
||||
Back to Clusters
|
||||
</Button>
|
||||
</div>
|
||||
@@ -241,8 +240,8 @@ export default function ClusterDetail() {
|
||||
? 'border-brand-500 text-brand-600 dark:text-brand-400'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
}`}
|
||||
startIcon={<FileIcon className="w-4 h-4" />}
|
||||
>
|
||||
<FileIcon className="w-4 h-4 inline mr-2" />
|
||||
Articles
|
||||
</Button>
|
||||
<Button
|
||||
@@ -253,8 +252,8 @@ export default function ClusterDetail() {
|
||||
? 'border-brand-500 text-brand-600 dark:text-brand-400'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
}`}
|
||||
startIcon={<PageIcon className="w-4 h-4" />}
|
||||
>
|
||||
<PageIcon className="w-4 h-4 inline mr-2" />
|
||||
Pages
|
||||
</Button>
|
||||
<Button
|
||||
@@ -265,8 +264,8 @@ export default function ClusterDetail() {
|
||||
? 'border-brand-500 text-brand-600 dark:text-brand-400'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
}`}
|
||||
startIcon={<GridIcon className="w-4 h-4" />}
|
||||
>
|
||||
<GridIcon className="w-4 h-4 inline mr-2" />
|
||||
Products
|
||||
</Button>
|
||||
<Button
|
||||
@@ -277,8 +276,8 @@ export default function ClusterDetail() {
|
||||
? 'border-brand-500 text-brand-600 dark:text-brand-400'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
}`}
|
||||
startIcon={<TagIcon className="w-4 h-4" />}
|
||||
>
|
||||
<TagIcon className="w-4 h-4 inline mr-2" />
|
||||
Taxonomy
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -28,7 +28,9 @@ import {
|
||||
PageIcon,
|
||||
TableIcon,
|
||||
ChevronDownIcon,
|
||||
ChevronUpIcon
|
||||
ChevronUpIcon,
|
||||
FilterIcon,
|
||||
BoxCubeIcon as SettingsIcon
|
||||
} from '../../icons';
|
||||
import {
|
||||
fetchSites,
|
||||
@@ -67,6 +69,7 @@ export default function SiteList() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [viewType, setViewType] = useState<ViewType>('grid');
|
||||
const [showWelcomeGuide, setShowWelcomeGuide] = useState(false);
|
||||
const [showFilters, setShowFilters] = useState(false);
|
||||
|
||||
// Site Management Modals
|
||||
const [selectedSite, setSelectedSite] = useState<Site | null>(null);
|
||||
@@ -410,19 +413,16 @@ export default function SiteList() {
|
||||
{site.domain}
|
||||
</p>
|
||||
)}
|
||||
<div className="flex items-center gap-2 mb-2 flex-wrap">
|
||||
<SiteTypeBadge hostingType={site.hosting_type} />
|
||||
{/* Centered badges with uniform size */}
|
||||
<div className="flex items-center justify-center gap-2 mb-2 flex-wrap">
|
||||
<SiteTypeBadge hostingType={site.hosting_type} size="sm" />
|
||||
{site.industry_name && (
|
||||
<Badge variant="light" color="info" className="text-xs">
|
||||
<Badge variant="soft" color="warning" size="sm">
|
||||
{site.industry_name}
|
||||
</Badge>
|
||||
)}
|
||||
{site.integration_count && site.integration_count > 0 && (
|
||||
<Badge variant="soft" color="success" className="text-[10px] px-1.5 py-0.5">
|
||||
{site.integration_count} integration{site.integration_count > 1 ? 's' : ''}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{/* Status badge and toggle in top right */}
|
||||
<div className="absolute top-4 right-4 flex items-center gap-3">
|
||||
<Switch
|
||||
checked={site.is_active}
|
||||
@@ -430,19 +430,21 @@ export default function SiteList() {
|
||||
disabled={togglingSiteId === site.id}
|
||||
/>
|
||||
<Badge
|
||||
variant={site.is_active ? "soft" : "light"}
|
||||
color={site.is_active ? "success" : "gray"}
|
||||
size="sm"
|
||||
variant="solid"
|
||||
color={site.is_active ? "success" : "error"}
|
||||
size="xs"
|
||||
>
|
||||
{site.is_active ? 'Active' : 'Inactive'}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
{/* Centered button row */}
|
||||
<div className="border-t border-gray-200 p-3 dark:border-gray-800">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div className="flex justify-center gap-2">
|
||||
<Button
|
||||
onClick={() => navigate(`/sites/${site.id}`)}
|
||||
variant="primary"
|
||||
tone="brand"
|
||||
size="sm"
|
||||
startIcon={<EyeIcon className="w-4 h-4" />}
|
||||
>
|
||||
@@ -451,6 +453,7 @@ export default function SiteList() {
|
||||
<Button
|
||||
onClick={() => navigate(`/sites/${site.id}/content`)}
|
||||
variant="secondary"
|
||||
tone="neutral"
|
||||
size="sm"
|
||||
startIcon={<FileIcon className="w-4 h-4" />}
|
||||
>
|
||||
@@ -459,9 +462,9 @@ export default function SiteList() {
|
||||
<Button
|
||||
onClick={() => navigate(`/sites/${site.id}/settings`)}
|
||||
variant="outline"
|
||||
tone="neutral"
|
||||
size="sm"
|
||||
startIcon={<PlugInIcon className="w-4 h-4" />}
|
||||
className="col-span-2"
|
||||
startIcon={<SettingsIcon className="w-4 h-4" />}
|
||||
>
|
||||
Settings
|
||||
</Button>
|
||||
@@ -497,33 +500,46 @@ export default function SiteList() {
|
||||
|
||||
{/* Custom Header Actions - Add Site button and view toggle */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-3">
|
||||
<Button
|
||||
onClick={() => setShowWelcomeGuide(!showWelcomeGuide)}
|
||||
variant="success"
|
||||
variant="primary"
|
||||
tone="brand"
|
||||
size="md"
|
||||
startIcon={<PlusIcon className="w-5 h-5" />}
|
||||
>
|
||||
Add New Website
|
||||
</Button>
|
||||
{viewType === 'grid' && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="md"
|
||||
onClick={() => setShowFilters(!showFilters)}
|
||||
startIcon={<FilterIcon className="w-4 h-4" />}
|
||||
>
|
||||
{showFilters ? 'Hide Filters' : 'Show Filters'}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded-lg p-1">
|
||||
<Button
|
||||
onClick={() => setViewType('table')}
|
||||
variant={viewType === 'table' ? 'secondary' : 'ghost'}
|
||||
variant={viewType === 'table' ? 'primary' : 'ghost'}
|
||||
tone="brand"
|
||||
size="sm"
|
||||
startIcon={<TableIcon className="w-4 h-4" />}
|
||||
>
|
||||
<span className="hidden sm:inline">Table</span>
|
||||
Table
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setViewType('grid')}
|
||||
variant={viewType === 'grid' ? 'secondary' : 'ghost'}
|
||||
variant={viewType === 'grid' ? 'primary' : 'ghost'}
|
||||
tone="brand"
|
||||
size="sm"
|
||||
startIcon={<GridIcon className="w-4 h-4" />}
|
||||
>
|
||||
<span className="hidden sm:inline">Grid</span>
|
||||
Grid
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -600,59 +616,61 @@ export default function SiteList() {
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{/* Standard Filters Bar for Grid View - Matches Table View */}
|
||||
<div className="flex justify-center mb-4">
|
||||
<div
|
||||
className="w-[75%] igny8-filter-bar p-3 rounded-lg bg-transparent shadow-theme-md"
|
||||
>
|
||||
<div className="flex flex-nowrap gap-3 items-center justify-between w-full">
|
||||
<div className="flex flex-nowrap gap-3 items-center flex-1 min-w-0 w-full">
|
||||
<div className="flex-1 min-w-[200px]">
|
||||
<InputField
|
||||
type="text"
|
||||
placeholder="Search sites..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 min-w-[140px]">
|
||||
<Select
|
||||
options={SITE_TYPES}
|
||||
placeholder="Show All Types"
|
||||
defaultValue={siteTypeFilter}
|
||||
onChange={(val) => setSiteTypeFilter(val)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 min-w-[140px]">
|
||||
<Select
|
||||
options={HOSTING_TYPES}
|
||||
placeholder="Show All Hosting"
|
||||
defaultValue={hostingTypeFilter}
|
||||
onChange={(val) => setHostingTypeFilter(val)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 min-w-[140px]">
|
||||
<Select
|
||||
options={STATUS_OPTIONS}
|
||||
placeholder="Show All Status"
|
||||
defaultValue={statusFilter}
|
||||
onChange={(val) => setStatusFilter(val)}
|
||||
/>
|
||||
{/* Standard Filters Bar for Grid View - Collapsible like table view */}
|
||||
{showFilters && (
|
||||
<div className="flex justify-center mb-4">
|
||||
<div
|
||||
className="w-full igny8-filter-bar p-3 rounded-lg bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 shadow-sm"
|
||||
>
|
||||
<div className="flex flex-nowrap gap-3 items-center justify-between w-full">
|
||||
<div className="flex flex-nowrap gap-3 items-center flex-1 min-w-0 w-full">
|
||||
<div className="flex-1 min-w-[200px]">
|
||||
<InputField
|
||||
type="text"
|
||||
placeholder="Search sites..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 min-w-[140px]">
|
||||
<Select
|
||||
options={SITE_TYPES}
|
||||
placeholder="Show All Types"
|
||||
defaultValue={siteTypeFilter}
|
||||
onChange={(val) => setSiteTypeFilter(val)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 min-w-[140px]">
|
||||
<Select
|
||||
options={HOSTING_TYPES}
|
||||
placeholder="Show All Hosting"
|
||||
defaultValue={hostingTypeFilter}
|
||||
onChange={(val) => setHostingTypeFilter(val)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 min-w-[140px]">
|
||||
<Select
|
||||
options={STATUS_OPTIONS}
|
||||
placeholder="Show All Status"
|
||||
defaultValue={statusFilter}
|
||||
onChange={(val) => setStatusFilter(val)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{hasActiveFilters && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={clearFilters}
|
||||
className="flex-shrink-0"
|
||||
>
|
||||
Clear Filters
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{hasActiveFilters && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={clearFilters}
|
||||
className="flex-shrink-0"
|
||||
>
|
||||
Clear Filters
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Grid View */}
|
||||
{filteredSites.length === 0 ? (
|
||||
@@ -665,7 +683,7 @@ export default function SiteList() {
|
||||
Clear Filters
|
||||
</Button>
|
||||
) : (
|
||||
<Button onClick={() => setShowWelcomeGuide(true)} variant="success" startIcon={<PlusIcon className="w-5 h-5" />}>
|
||||
<Button onClick={() => setShowWelcomeGuide(true)} variant="primary" tone="success" startIcon={<PlusIcon className="w-5 h-5" />}>
|
||||
Add Your First Site
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -11,6 +11,7 @@ import PageMeta from '../../components/common/PageMeta';
|
||||
import PageHeader from '../../components/common/PageHeader';
|
||||
import { Card } from '../../components/ui/card';
|
||||
import Button from '../../components/ui/button/Button';
|
||||
import IconButton from '../../components/ui/button/IconButton';
|
||||
import { useToast } from '../../components/ui/toast/ToastContainer';
|
||||
import { fetchAPI } from '../../services/api';
|
||||
import {
|
||||
@@ -94,13 +95,10 @@ const DraggablePageItem: React.FC<{
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" size="sm" onClick={() => onEdit(page.id)}>
|
||||
<PencilIcon className="w-4 h-4 mr-1" />
|
||||
<Button variant="outline" size="sm" onClick={() => onEdit(page.id)} startIcon={<PencilIcon className="w-4 h-4" />}>
|
||||
Edit
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm" onClick={() => onDelete(page.id)}>
|
||||
<TrashBinIcon className="w-4 h-4" />
|
||||
</Button>
|
||||
<IconButton variant="ghost" size="sm" onClick={() => onDelete(page.id)} icon={<TrashBinIcon className="w-4 h-4" />} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -330,8 +328,8 @@ export default function PageManager() {
|
||||
size="sm"
|
||||
onClick={handleBulkDelete}
|
||||
className="text-error-600 hover:text-error-700"
|
||||
startIcon={<TrashBinIcon className="w-4 h-4" />}
|
||||
>
|
||||
<TrashBinIcon className="w-4 h-4 mr-1" />
|
||||
Delete Selected
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm" onClick={() => setSelectedPages(new Set())}>
|
||||
|
||||
@@ -271,16 +271,16 @@ export default function PostEditor() {
|
||||
variant={activeTab === 'content' ? 'primary' : 'ghost'}
|
||||
size="sm"
|
||||
onClick={() => setActiveTab('content')}
|
||||
startIcon={<FileTextIcon className="w-4 h-4" />}
|
||||
>
|
||||
<FileTextIcon className="w-4 h-4" />
|
||||
Content
|
||||
</Button>
|
||||
<Button
|
||||
variant={activeTab === 'taxonomy' ? 'primary' : 'ghost'}
|
||||
size="sm"
|
||||
onClick={() => setActiveTab('taxonomy')}
|
||||
startIcon={<TagIcon className="w-4 h-4" />}
|
||||
>
|
||||
<TagIcon className="w-4 h-4" />
|
||||
Taxonomy & Cluster
|
||||
</Button>
|
||||
{content.id && (
|
||||
@@ -291,8 +291,8 @@ export default function PostEditor() {
|
||||
setActiveTab('validation');
|
||||
loadValidation();
|
||||
}}
|
||||
startIcon={<CheckCircleIcon className="w-4 h-4" />}
|
||||
>
|
||||
<CheckCircleIcon className="w-4 h-4" />
|
||||
Validation
|
||||
{validationResult && !validationResult.is_valid && (
|
||||
<span className="ml-2 px-2 py-0.5 text-xs bg-error-100 dark:bg-error-900 text-error-600 dark:text-error-400 rounded-full">
|
||||
|
||||
@@ -283,15 +283,15 @@ export default function PublishingQueue() {
|
||||
<ButtonGroupItem
|
||||
isActive={viewMode === 'list'}
|
||||
onClick={() => setViewMode('list')}
|
||||
startIcon={<ListIcon className="w-4 h-4" />}
|
||||
>
|
||||
<ListIcon className="w-4 h-4 mr-1.5" />
|
||||
List
|
||||
</ButtonGroupItem>
|
||||
<ButtonGroupItem
|
||||
isActive={viewMode === 'calendar'}
|
||||
onClick={() => setViewMode('calendar')}
|
||||
startIcon={<CalendarIcon className="w-4 h-4" />}
|
||||
>
|
||||
<CalendarIcon className="w-4 h-4 mr-1.5" />
|
||||
Calendar
|
||||
</ButtonGroupItem>
|
||||
</ButtonGroup>
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
} from '../../services/api';
|
||||
import WordPressIntegrationForm from '../../components/sites/WordPressIntegrationForm';
|
||||
import { integrationApi, SiteIntegration } from '../../services/integration.api';
|
||||
import { GridIcon, PlugInIcon, PaperPlaneIcon, DocsIcon, BoltIcon, FileIcon, ChevronDownIcon, CloseIcon, PlusIcon } from '../../icons';
|
||||
import { GridIcon, PlugInIcon, PaperPlaneIcon, DocsIcon, BoltIcon, FileIcon, ChevronDownIcon, CloseIcon, PlusIcon, RefreshCwIcon } from '../../icons';
|
||||
import Badge from '../../components/ui/badge/Badge';
|
||||
import { Dropdown } from '../../components/ui/dropdown/Dropdown';
|
||||
import { DropdownItem } from '../../components/ui/dropdown/DropdownItem';
|
||||
@@ -621,8 +621,8 @@ export default function SiteSettings() {
|
||||
? 'border-brand-500 text-brand-600 dark:text-brand-400'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
}`}
|
||||
startIcon={<GridIcon className="w-4 h-4" />}
|
||||
>
|
||||
<GridIcon className="w-4 h-4 inline mr-2" />
|
||||
General
|
||||
</Button>
|
||||
<Button
|
||||
@@ -636,8 +636,8 @@ export default function SiteSettings() {
|
||||
? 'border-brand-500 text-brand-600 dark:text-brand-400'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
}`}
|
||||
startIcon={<PlugInIcon className="w-4 h-4" />}
|
||||
>
|
||||
<PlugInIcon className="w-4 h-4 inline mr-2" />
|
||||
Integrations
|
||||
</Button>
|
||||
<Button
|
||||
@@ -651,8 +651,8 @@ export default function SiteSettings() {
|
||||
? 'border-brand-500 text-brand-600 dark:text-brand-400'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
}`}
|
||||
startIcon={<PaperPlaneIcon className="w-4 h-4" />}
|
||||
>
|
||||
<PaperPlaneIcon className="w-4 h-4 inline mr-2" />
|
||||
Publishing
|
||||
</Button>
|
||||
{(wordPressIntegration || site?.wp_url || site?.wp_api_key || site?.hosting_type === 'wordpress') && (
|
||||
@@ -667,8 +667,8 @@ export default function SiteSettings() {
|
||||
? 'border-brand-500 text-brand-600 dark:text-brand-400'
|
||||
: 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
}`}
|
||||
startIcon={<FileIcon className="w-4 h-4" />}
|
||||
>
|
||||
<FileIcon className="w-4 h-4 inline mr-2" />
|
||||
Content Types
|
||||
</Button>
|
||||
)}
|
||||
@@ -951,21 +951,9 @@ export default function SiteSettings() {
|
||||
variant="outline"
|
||||
disabled={syncLoading || !(wordPressIntegration || site?.wp_url || site?.wp_api_key || site?.hosting_type === 'wordpress')}
|
||||
onClick={handleManualSync}
|
||||
className="flex items-center gap-2"
|
||||
startIcon={syncLoading ? <RefreshCwIcon className="w-4 h-4 animate-spin" /> : <RefreshCwIcon className="w-4 h-4" />}
|
||||
>
|
||||
{syncLoading ? (
|
||||
<>
|
||||
<div className="inline-block animate-spin rounded-full h-4 w-4 border-b-2 border-current"></div>
|
||||
<span>Syncing...</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
<span>Sync Structure</span>
|
||||
</>
|
||||
)}
|
||||
{syncLoading ? 'Syncing...' : 'Sync Structure'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -252,8 +252,8 @@ export default function SyncDashboard() {
|
||||
size="sm"
|
||||
onClick={() => handleSync('to_external')}
|
||||
disabled={syncing || !integration.sync_enabled}
|
||||
startIcon={<ArrowRightIcon className="w-4 h-4" />}
|
||||
>
|
||||
<ArrowRightIcon className="w-4 h-4 mr-1" />
|
||||
Sync to WordPress
|
||||
</Button>
|
||||
<Button
|
||||
@@ -261,8 +261,8 @@ export default function SyncDashboard() {
|
||||
size="sm"
|
||||
onClick={() => handleSync('from_external')}
|
||||
disabled={syncing || !integration.sync_enabled}
|
||||
startIcon={<ArrowRightIcon className="w-4 h-4 rotate-180" />}
|
||||
>
|
||||
<ArrowRightIcon className="w-4 h-4 mr-1 rotate-180" />
|
||||
Sync from WordPress
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -107,8 +107,7 @@ export default function AuthorProfiles() {
|
||||
breadcrumb="Thinker / Author Profiles"
|
||||
/>
|
||||
<div className="mb-6 flex justify-between items-center">
|
||||
<Button onClick={handleCreate} variant="primary">
|
||||
<PlusIcon className="w-4 h-4 mr-2" />
|
||||
<Button onClick={handleCreate} variant="primary" startIcon={<PlusIcon className="w-4 h-4" />}>
|
||||
Create Profile
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import {
|
||||
SaveIcon, Loader2Icon, SettingsIcon, UserIcon, UsersIcon, UserIcon as UserPlusIcon, LockIcon, LockIcon as ShieldIcon, XIcon
|
||||
SaveIcon, Loader2Icon, SettingsIcon, UserIcon, UsersIcon, UserPlusIcon, LockIcon, LockIcon as ShieldIcon, XIcon
|
||||
} from '../../icons';
|
||||
import { Card } from '../../components/ui/card';
|
||||
import Button from '../../components/ui/button/Button';
|
||||
@@ -605,7 +605,7 @@ export default function AccountSettingsPage() {
|
||||
<Button
|
||||
variant="primary"
|
||||
tone="brand"
|
||||
startIcon={<UserPlus className="w-4 h-4" />}
|
||||
startIcon={<UserPlusIcon className="w-4 h-4" />}
|
||||
onClick={() => setShowInviteModal(true)}
|
||||
>
|
||||
Invite Someone
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import {
|
||||
SaveIcon, Loader2Icon, ImageIcon, FileTextIcon, PaperPlaneIcon as SendIcon, SettingsIcon
|
||||
SaveIcon, Loader2Icon, ImageIcon, FileTextIcon, PaperPlaneIcon, SettingsIcon
|
||||
} from '../../icons';
|
||||
import { Card } from '../../components/ui/card';
|
||||
import Button from '../../components/ui/button/Button';
|
||||
|
||||
@@ -209,9 +209,8 @@ export default function NotificationsPage() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setShowFilters(!showFilters)}
|
||||
className="flex items-center gap-2"
|
||||
startIcon={<FilterIcon className="w-4 h-4" />}
|
||||
>
|
||||
<FilterIcon className="w-4 h-4" />
|
||||
Filters
|
||||
</Button>
|
||||
|
||||
@@ -220,9 +219,8 @@ export default function NotificationsPage() {
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleMarkAllRead}
|
||||
className="flex items-center gap-2"
|
||||
startIcon={<CheckCheckIcon className="w-4 h-4" />}
|
||||
>
|
||||
<CheckCheckIcon className="w-4 h-4" />
|
||||
Mark All Read
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import {
|
||||
CreditCardIcon, BoxIcon as PackageIcon, TrendingUpIcon, FileTextIcon, WalletIcon, ArrowUpIcon as ArrowUpCircleIcon,
|
||||
CreditCardIcon, BoxIcon as PackageIcon, TrendingUpIcon, FileTextIcon, WalletIcon, ArrowUpIcon,
|
||||
Loader2Icon, AlertCircleIcon, CheckCircleIcon, DownloadIcon, ZapIcon, GlobeIcon, UsersIcon, XIcon
|
||||
} from '../../icons';
|
||||
import { Card } from '../../components/ui/card';
|
||||
|
||||
@@ -763,8 +763,8 @@ export default function ContentViewTemplate({ content, loading, onBack }: Conten
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={onBack}
|
||||
startIcon={<ArrowLeftIcon className="w-4 h-4" />}
|
||||
>
|
||||
<ArrowLeftIcon className="w-4 h-4" />
|
||||
Back to Content List
|
||||
</Button>
|
||||
)}
|
||||
@@ -829,8 +829,8 @@ export default function ContentViewTemplate({ content, loading, onBack }: Conten
|
||||
variant="ghost"
|
||||
onClick={onBack}
|
||||
className="mb-6"
|
||||
startIcon={<ArrowLeftIcon className="w-4 h-4" />}
|
||||
>
|
||||
<ArrowLeftIcon className="w-4 h-4" />
|
||||
Back to Content List
|
||||
</Button>
|
||||
)}
|
||||
@@ -1030,16 +1030,16 @@ export default function ContentViewTemplate({ content, loading, onBack }: Conten
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => navigate(`/sites/${content.site_id}/posts/${content.id}/edit`)}
|
||||
startIcon={<PencilIcon className="w-4 h-4" />}
|
||||
>
|
||||
<PencilIcon className="w-4 h-4" />
|
||||
Edit Content
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
tone="brand"
|
||||
onClick={() => navigate(`/writer/images?contentId=${content.id}`)}
|
||||
startIcon={<ImageIcon className="w-4 h-4" />}
|
||||
>
|
||||
<ImageIcon className="w-4 h-4" />
|
||||
Generate Images
|
||||
</Button>
|
||||
</>
|
||||
@@ -1051,16 +1051,16 @@ export default function ContentViewTemplate({ content, loading, onBack }: Conten
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => navigate(`/sites/${content.site_id}/posts/${content.id}/edit`)}
|
||||
startIcon={<PencilIcon className="w-4 h-4" />}
|
||||
>
|
||||
<PencilIcon className="w-4 h-4" />
|
||||
Edit Content
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
tone="brand"
|
||||
onClick={() => navigate(`/writer/published?contentId=${content.id}&action=publish`)}
|
||||
startIcon={<BoltIcon className="w-4 h-4" />}
|
||||
>
|
||||
<BoltIcon className="w-4 h-4" />
|
||||
Publish
|
||||
</Button>
|
||||
</>
|
||||
|
||||