@codeswayam/ui 1.1.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +727 -173
- package/dist/components/base/badge.d.ts +1 -1
- package/dist/components/base/button.d.ts +2 -2
- package/dist/components/base/button.d.ts.map +1 -1
- package/dist/components/base/button.js +2 -2
- package/dist/components/brand/BrandFooterSection.d.ts +8 -0
- package/dist/components/brand/BrandFooterSection.d.ts.map +1 -0
- package/dist/components/brand/BrandFooterSection.js +97 -0
- package/dist/components/brand/BrandNav.d.ts +17 -0
- package/dist/components/brand/BrandNav.d.ts.map +1 -0
- package/dist/components/brand/BrandNav.js +64 -0
- package/dist/components/data/DataTable.d.ts +18 -0
- package/dist/components/data/DataTable.d.ts.map +1 -0
- package/dist/components/data/DataTable.js +36 -0
- package/dist/components/data/EmptyState.d.ts +23 -0
- package/dist/components/data/EmptyState.d.ts.map +1 -0
- package/dist/components/data/EmptyState.js +9 -0
- package/dist/components/data/TableToolbar.d.ts +17 -0
- package/dist/components/data/TableToolbar.d.ts.map +1 -0
- package/dist/components/data/TableToolbar.js +21 -0
- package/dist/components/display/CopyButton.d.ts +14 -0
- package/dist/components/display/CopyButton.d.ts.map +1 -0
- package/dist/components/display/CopyButton.js +37 -0
- package/dist/components/display/PageHeader.d.ts +11 -0
- package/dist/components/display/PageHeader.d.ts.map +1 -0
- package/dist/components/display/PageHeader.js +5 -0
- package/dist/components/display/StatCard.d.ts +23 -0
- package/dist/components/display/StatCard.d.ts.map +1 -0
- package/dist/components/display/StatCard.js +6 -0
- package/dist/components/feedback/ConfirmDialog.d.ts +18 -0
- package/dist/components/feedback/ConfirmDialog.d.ts.map +1 -0
- package/dist/components/feedback/ConfirmDialog.js +10 -0
- package/dist/components/feedback/ErrorState.d.ts +10 -0
- package/dist/components/feedback/ErrorState.d.ts.map +1 -0
- package/dist/components/feedback/ErrorState.js +7 -0
- package/dist/components/feedback/Skeleton.d.ts +26 -0
- package/dist/components/feedback/Skeleton.d.ts.map +1 -0
- package/dist/components/feedback/Skeleton.js +31 -0
- package/dist/components/neural/AICreditBadge.d.ts +9 -0
- package/dist/components/neural/AICreditBadge.d.ts.map +1 -0
- package/dist/components/neural/AICreditBadge.js +31 -0
- package/dist/components/neural/AIImageGeneratorModal.d.ts +9 -0
- package/dist/components/neural/AIImageGeneratorModal.d.ts.map +1 -0
- package/dist/components/neural/AIImageGeneratorModal.js +66 -0
- package/dist/components/neural/AIPromptPlayground.d.ts +10 -0
- package/dist/components/neural/AIPromptPlayground.d.ts.map +1 -0
- package/dist/components/neural/AIPromptPlayground.js +66 -0
- package/dist/components/neural/KnowledgeBasePicker.d.ts +18 -0
- package/dist/components/neural/KnowledgeBasePicker.d.ts.map +1 -0
- package/dist/components/neural/KnowledgeBasePicker.js +42 -0
- package/dist/components/neural/WorkflowPicker.d.ts +18 -0
- package/dist/components/neural/WorkflowPicker.d.ts.map +1 -0
- package/dist/components/neural/WorkflowPicker.js +46 -0
- package/dist/components/neural/index.d.ts +11 -0
- package/dist/components/neural/index.d.ts.map +1 -0
- package/dist/components/neural/index.js +5 -0
- package/dist/components/saas/NotificationBell.d.ts +12 -0
- package/dist/components/saas/NotificationBell.d.ts.map +1 -0
- package/dist/components/saas/NotificationBell.js +52 -0
- package/dist/components/saas/status-badge.d.ts +15 -8
- package/dist/components/saas/status-badge.d.ts.map +1 -1
- package/dist/components/saas/status-badge.js +46 -25
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/useNotifications.d.ts +24 -0
- package/dist/utils/useNotifications.d.ts.map +1 -0
- package/dist/utils/useNotifications.js +71 -0
- package/dist/utils/useWebPush.d.ts +14 -0
- package/dist/utils/useWebPush.d.ts.map +1 -0
- package/dist/utils/useWebPush.js +110 -0
- package/package.json +4 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
declare const badgeVariants: (props?: ({
|
|
4
|
-
variant?: "default" | "
|
|
4
|
+
variant?: "default" | "secondary" | "destructive" | "outline" | "success" | "warning" | "info" | "purple" | null | undefined;
|
|
5
5
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
6
|
export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
|
|
7
7
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
|
-
variant?: "link" | "default" | "
|
|
5
|
-
size?: "
|
|
4
|
+
variant?: "link" | "default" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
|
|
5
|
+
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
8
8
|
asChild?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/components/base/button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,QAAA,MAAM,cAAc;;;8EAwBnB,CAAC;AAEF,MAAM,WAAW,WACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EACnD,YAAY,CAAC,OAAO,cAAc,CAAC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,QAAA,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/components/base/button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,QAAA,MAAM,cAAc;;;8EAwBnB,CAAC;AAEF,MAAM,WAAW,WACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EACnD,YAAY,CAAC,OAAO,cAAc,CAAC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,QAAA,MAAM,MAAM,uFAYX,CAAC;AAGF,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -25,9 +25,9 @@ const buttonVariants = cva("inline-flex items-center justify-center gap-2 whites
|
|
|
25
25
|
size: "default",
|
|
26
26
|
},
|
|
27
27
|
});
|
|
28
|
-
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
28
|
+
const Button = React.forwardRef(({ className, variant, size, asChild = false, disabled, ...props }, ref) => {
|
|
29
29
|
const Comp = (asChild ? Slot : "button");
|
|
30
|
-
return (_jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref: ref, ...props }));
|
|
30
|
+
return (_jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref: ref, disabled: disabled === true, ...props }));
|
|
31
31
|
});
|
|
32
32
|
Button.displayName = "Button";
|
|
33
33
|
export { Button, buttonVariants };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface BrandFooterSectionProps {
|
|
2
|
+
currentApp?: 'codeswayam' | 'pixelforge' | 'pdfcraft' | 'neural' | 'auraflow';
|
|
3
|
+
theme?: 'auto' | 'light' | 'dark';
|
|
4
|
+
className?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function BrandFooterSection({ currentApp, theme, className, }: BrandFooterSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=BrandFooterSection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrandFooterSection.d.ts","sourceRoot":"","sources":["../../../src/components/brand/BrandFooterSection.tsx"],"names":[],"mappings":"AAKA,UAAU,uBAAuB;IAC/B,UAAU,CAAC,EAAE,YAAY,GAAG,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC9E,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAqCD,wBAAgB,kBAAkB,CAAC,EACjC,UAAU,EACV,KAAc,EACd,SAAc,GACf,EAAE,uBAAuB,2CA2JzB"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Layers, Sparkles, FileText, Bot, ArrowUpRight } from 'lucide-react';
|
|
4
|
+
const BRAND_CARDS = [
|
|
5
|
+
{
|
|
6
|
+
name: 'Code Swayam',
|
|
7
|
+
slug: 'codeswayam',
|
|
8
|
+
url: 'https://codeswayam.com',
|
|
9
|
+
icon: Layers,
|
|
10
|
+
desc: 'Central platform, design systems, and digital product portfolio.',
|
|
11
|
+
iconColor: 'text-blue-500 bg-blue-500/10 border-blue-500/20',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: 'PixelForge',
|
|
15
|
+
slug: 'pixelforge',
|
|
16
|
+
url: 'https://pixelforge.codeswayam.com',
|
|
17
|
+
icon: Sparkles,
|
|
18
|
+
desc: '50+ free image tools: compress JPG to 20KB, convert WebP, resize for portals.',
|
|
19
|
+
iconColor: 'text-purple-500 bg-purple-500/10 border-purple-500/20',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'PDFCraft',
|
|
23
|
+
slug: 'pdfcraft',
|
|
24
|
+
url: 'https://pdfcraft.codeswayam.com',
|
|
25
|
+
icon: FileText,
|
|
26
|
+
desc: 'Fast, secure PDF tools: compress to 100KB, merge, split, sign & convert.',
|
|
27
|
+
iconColor: 'text-emerald-500 bg-emerald-500/10 border-emerald-500/20',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'Neural AI',
|
|
31
|
+
slug: 'neural',
|
|
32
|
+
url: 'https://neural.codeswayam.com',
|
|
33
|
+
icon: Bot,
|
|
34
|
+
desc: 'Unified multi-model AI studio, image generation, and API gateways.',
|
|
35
|
+
iconColor: 'text-amber-500 bg-amber-500/10 border-amber-500/20',
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
export function BrandFooterSection({ currentApp, theme = 'auto', className = '', }) {
|
|
39
|
+
const isDark = theme === 'dark';
|
|
40
|
+
const schemaOrg = {
|
|
41
|
+
'@context': 'https://schema.org',
|
|
42
|
+
'@type': 'Organization',
|
|
43
|
+
name: 'Code Swayam',
|
|
44
|
+
url: 'https://codeswayam.com',
|
|
45
|
+
logo: 'https://codeswayam.com/logo.png',
|
|
46
|
+
sameAs: [
|
|
47
|
+
'https://twitter.com/codeswayam',
|
|
48
|
+
'https://linkedin.com/company/codeswayam',
|
|
49
|
+
'https://github.com/codeswayam',
|
|
50
|
+
],
|
|
51
|
+
hasPart: [
|
|
52
|
+
{
|
|
53
|
+
'@type': 'WebApplication',
|
|
54
|
+
name: 'PixelForge',
|
|
55
|
+
url: 'https://pixelforge.codeswayam.com',
|
|
56
|
+
applicationCategory: 'MultimediaApplication',
|
|
57
|
+
operatingSystem: 'All',
|
|
58
|
+
description: 'Free image compression, conversion, resizing, and AI editing suite.',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
'@type': 'WebApplication',
|
|
62
|
+
name: 'PDFCraft',
|
|
63
|
+
url: 'https://pdfcraft.codeswayam.com',
|
|
64
|
+
applicationCategory: 'UtilitiesApplication',
|
|
65
|
+
operatingSystem: 'All',
|
|
66
|
+
description: 'Free browser-based PDF compression, merge, split, and conversion suite.',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
'@type': 'WebApplication',
|
|
70
|
+
name: 'Neural AI',
|
|
71
|
+
url: 'https://neural.codeswayam.com',
|
|
72
|
+
applicationCategory: 'ArtificialIntelligenceApplication',
|
|
73
|
+
operatingSystem: 'All',
|
|
74
|
+
description: 'Enterprise generative AI studio, multi-model gateway, and automation platform.',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
'@type': 'WebApplication',
|
|
78
|
+
name: 'AuraFlow',
|
|
79
|
+
url: 'https://auraflow.codeswayam.com',
|
|
80
|
+
applicationCategory: 'DeveloperApplication',
|
|
81
|
+
operatingSystem: 'All',
|
|
82
|
+
description: 'High-performance cloud infrastructure and microservice automation fabric.',
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
return (_jsxs(_Fragment, { children: [_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(schemaOrg) } }), _jsx("div", { className: `border-t pt-12 pb-8 ${isDark ? 'border-white/10 text-white' : 'border-border/60 text-foreground'} ${className}`, children: _jsxs("div", { className: "max-w-7xl mx-auto px-6", children: [_jsxs("div", { className: "flex flex-col md:flex-row md:items-center justify-between gap-6 mb-8", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2 mb-1.5", children: [_jsx("span", { className: "w-2 h-2 rounded-full bg-primary" }), _jsx("span", { className: `text-[11px] font-black uppercase tracking-[0.2em] ${isDark ? 'text-white' : 'text-foreground'}`, children: "The CodeSwayam Product Ecosystem" })] }), _jsx("p", { className: `text-xs max-w-xl leading-relaxed ${isDark ? 'text-white/60' : 'text-muted-foreground'}`, children: "Interconnected developer, media, and artificial intelligence tools engineered for speed, privacy, and zero bloat." })] }), _jsxs("a", { href: "https://codeswayam.com/tools", className: "inline-flex items-center gap-2 px-4 py-2 rounded-xl bg-primary/10 hover:bg-primary text-primary hover:text-primary-foreground text-xs font-bold uppercase tracking-wider transition-all shrink-0 shadow-sm", children: ["Explore 150+ Free Tools Directory", _jsx(ArrowUpRight, { className: "w-3.5 h-3.5" })] })] }), _jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4", children: BRAND_CARDS.map((card) => {
|
|
87
|
+
const Icon = card.icon;
|
|
88
|
+
const isCurrent = currentApp === card.slug;
|
|
89
|
+
return (_jsx("a", { href: card.url, className: `group p-5 rounded-2xl border transition-all duration-300 flex flex-col justify-between ${isDark
|
|
90
|
+
? isCurrent
|
|
91
|
+
? 'border-primary/50 bg-primary/10'
|
|
92
|
+
: 'border-white/10 hover:border-primary/40 bg-white/[0.03] hover:bg-white/[0.06]'
|
|
93
|
+
: isCurrent
|
|
94
|
+
? 'border-primary/40 bg-primary/5'
|
|
95
|
+
: 'border-border hover:border-primary/40 bg-card hover:bg-card/80 shadow-sm'}`, children: _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-3 mb-2.5", children: [_jsx("div", { className: `w-9 h-9 rounded-xl flex items-center justify-center shrink-0 border ${card.iconColor}`, children: _jsx(Icon, { className: "w-4 h-4" }) }), _jsx("div", { className: "min-w-0 flex-1", children: _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: `text-xs font-bold truncate group-hover:text-primary transition-colors ${isDark ? 'text-white' : 'text-foreground'}`, children: card.name }), isCurrent && (_jsx("span", { className: "w-2 h-2 rounded-full bg-primary shrink-0 animate-pulse", title: "Current Active App" }))] }) })] }), _jsx("p", { className: `text-[11px] leading-relaxed line-clamp-2 ${isDark ? 'text-white/60' : 'text-muted-foreground'}`, children: card.desc })] }) }, card.name));
|
|
96
|
+
}) })] }) })] }));
|
|
97
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface EcosystemApp {
|
|
3
|
+
name: string;
|
|
4
|
+
tagline: string;
|
|
5
|
+
url: string;
|
|
6
|
+
icon: React.ElementType;
|
|
7
|
+
badge?: string;
|
|
8
|
+
color: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const ECOSYSTEM_APPS: EcosystemApp[];
|
|
11
|
+
interface BrandAppSwitcherProps {
|
|
12
|
+
currentApp?: 'codeswayam' | 'pixelforge' | 'pdfcraft' | 'neural' | 'auraflow';
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function BrandAppSwitcher({ currentApp, className }: BrandAppSwitcherProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=BrandNav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrandNav.d.ts","sourceRoot":"","sources":["../../../src/components/brand/BrandNav.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAY3D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,KAAK,CAAC,WAAW,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,cAAc,EAAE,YAAY,EAuCxC,CAAC;AAEF,UAAU,qBAAqB;IAC7B,UAAU,CAAC,EAAE,YAAY,GAAG,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,gBAAgB,CAAC,EAAE,UAAU,EAAE,SAAc,EAAE,EAAE,qBAAqB,2CAuGrF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useRef, useEffect } from 'react';
|
|
4
|
+
import { Grid, Sparkles, FileText, Zap, Bot, ArrowRight, ExternalLink, Layers, } from 'lucide-react';
|
|
5
|
+
export const ECOSYSTEM_APPS = [
|
|
6
|
+
{
|
|
7
|
+
name: 'Code Swayam',
|
|
8
|
+
tagline: 'Enterprise Digital Ecosystem & Platform',
|
|
9
|
+
url: 'https://codeswayam.com',
|
|
10
|
+
icon: Layers,
|
|
11
|
+
color: 'text-blue-500 bg-blue-500/10 border-blue-500/20',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: 'PixelForge',
|
|
15
|
+
tagline: '50+ Free High-Speed Image Tools (Compress, Convert, AI)',
|
|
16
|
+
url: 'https://pixelforge.codeswayam.com',
|
|
17
|
+
icon: Sparkles,
|
|
18
|
+
badge: 'Popular',
|
|
19
|
+
color: 'text-purple-500 bg-purple-500/10 border-purple-500/20',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'PDFCraft',
|
|
23
|
+
tagline: 'Browser-Based PDF Suite (Merge, Compress, Convert, Sign)',
|
|
24
|
+
url: 'https://pdfcraft.codeswayam.com',
|
|
25
|
+
icon: FileText,
|
|
26
|
+
badge: 'Free',
|
|
27
|
+
color: 'text-emerald-500 bg-emerald-500/10 border-emerald-500/20',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'Neural AI',
|
|
31
|
+
tagline: 'Multi-Model AI Gateway, Studio & Workflow Automation',
|
|
32
|
+
url: 'https://neural.codeswayam.com',
|
|
33
|
+
icon: Bot,
|
|
34
|
+
badge: 'AI',
|
|
35
|
+
color: 'text-amber-500 bg-amber-500/10 border-amber-500/20',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'AuraFlow',
|
|
39
|
+
tagline: 'Cloud Infrastructure, Pipelines & Microservice Fabric',
|
|
40
|
+
url: 'https://auraflow.codeswayam.com',
|
|
41
|
+
icon: Zap,
|
|
42
|
+
color: 'text-rose-500 bg-rose-500/10 border-rose-500/20',
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
export function BrandAppSwitcher({ currentApp, className = '' }) {
|
|
46
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
47
|
+
const menuRef = useRef(null);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
function handleClickOutside(event) {
|
|
50
|
+
if (menuRef.current && !menuRef.current.contains(event.target)) {
|
|
51
|
+
setIsOpen(false);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
55
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
56
|
+
}, []);
|
|
57
|
+
return (_jsxs("div", { className: `relative inline-flex items-center ${className}`, ref: menuRef, children: [_jsxs("button", { onClick: () => setIsOpen(!isOpen), className: "inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full border border-border/70 bg-muted/40 hover:bg-muted text-muted-foreground hover:text-foreground transition-all cursor-pointer text-[11px] font-bold uppercase tracking-wider", title: "CodeSwayam Ecosystem Apps", "aria-label": "CodeSwayam Ecosystem Apps", "aria-expanded": isOpen, children: [_jsx(Grid, { className: "w-3.5 h-3.5 shrink-0 text-primary" }), _jsx("span", { children: "Apps" })] }), isOpen && (_jsxs("div", { className: "absolute right-0 top-full mt-2 w-80 md:w-96 rounded-2xl bg-card border border-border p-3 shadow-2xl z-50 animate-in fade-in zoom-in-95 duration-150", children: [_jsxs("div", { className: "px-3 py-2 border-b border-border mb-2 flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "w-2 h-2 rounded-full bg-primary animate-pulse" }), _jsx("span", { className: "text-xs font-black uppercase tracking-wider text-foreground", children: "CodeSwayam Ecosystem" })] }), _jsxs("a", { href: "https://codeswayam.com/tools", className: "text-[10px] font-bold uppercase tracking-wider text-primary hover:underline flex items-center gap-1", children: ["All Tools ", _jsx(ExternalLink, { className: "w-2.5 h-2.5" })] })] }), _jsx("div", { className: "space-y-1", children: ECOSYSTEM_APPS.map((app) => {
|
|
58
|
+
const Icon = app.icon;
|
|
59
|
+
const isCurrent = currentApp && app.url.toLowerCase().includes(currentApp.toLowerCase());
|
|
60
|
+
return (_jsxs("a", { href: app.url, className: `flex items-start gap-3 p-2.5 rounded-xl transition-all ${isCurrent
|
|
61
|
+
? 'bg-primary/10 border border-primary/20'
|
|
62
|
+
: 'hover:bg-muted/60 border border-transparent hover:border-border/60'}`, children: [_jsx("div", { className: `w-9 h-9 rounded-xl flex items-center justify-center shrink-0 border ${app.color}`, children: _jsx(Icon, { className: "w-4 h-4" }) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-bold text-xs text-foreground truncate", children: app.name }), app.badge && (_jsx("span", { className: "px-1.5 py-0.5 rounded text-[9px] font-black uppercase tracking-widest bg-primary/20 text-primary", children: app.badge })), isCurrent && (_jsx("span", { className: "text-[9px] text-muted-foreground font-medium ml-auto", children: "Current" }))] }), _jsx("p", { className: "text-[11px] text-muted-foreground line-clamp-1 mt-0.5", children: app.tagline })] })] }, app.name));
|
|
63
|
+
}) }), _jsxs("div", { className: "mt-3 pt-2.5 border-t border-border px-3 py-1.5 flex items-center justify-between text-xs text-muted-foreground bg-muted/20 rounded-xl", children: [_jsx("span", { children: "150+ free tools & services" }), _jsxs("a", { href: "https://codeswayam.com/tools", className: "font-bold text-foreground hover:text-primary flex items-center gap-1 transition-colors", children: ["Explore Directory ", _jsx(ArrowRight, { className: "w-3 h-3" })] })] })] }))] }));
|
|
64
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ColumnDef } from '@tanstack/react-table';
|
|
2
|
+
interface DataTableProps<TData, TValue> {
|
|
3
|
+
columns: ColumnDef<TData, TValue>[];
|
|
4
|
+
data: TData[];
|
|
5
|
+
/** Optional title rendered above the table */
|
|
6
|
+
title?: string;
|
|
7
|
+
/** Optional description rendered below the title */
|
|
8
|
+
description?: string;
|
|
9
|
+
/** Page size options. Defaults to [10, 25, 50] */
|
|
10
|
+
pageSizeOptions?: number[];
|
|
11
|
+
/** Default page size. Defaults to 10 */
|
|
12
|
+
defaultPageSize?: number;
|
|
13
|
+
/** Extra className on the wrapper */
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function DataTable<TData, TValue>({ columns, data, title, description, pageSizeOptions, defaultPageSize, className, }: DataTableProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=DataTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/components/data/DataTable.tsx"],"names":[],"mappings":"AAEA,OAAO,EAQL,SAAS,EAGV,MAAM,uBAAuB,CAAC;AAK/B,UAAU,cAAc,CAAC,KAAK,EAAE,MAAM;IACpC,OAAO,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;IACpC,IAAI,EAAE,KAAK,EAAE,CAAC;IACd,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,wCAAwC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EACvC,OAAO,EACP,IAAI,EACJ,KAAK,EACL,WAAW,EACX,eAA8B,EAC9B,eAAoB,EACpB,SAAS,GACV,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,2CAoK/B"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { flexRender, getCoreRowModel, getPaginationRowModel, getSortedRowModel, getFilteredRowModel, useReactTable, } from '@tanstack/react-table';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, ArrowUpDown, ArrowUp, ArrowDown } from 'lucide-react';
|
|
6
|
+
import { cn } from '../../utils/cn';
|
|
7
|
+
export function DataTable({ columns, data, title, description, pageSizeOptions = [10, 25, 50], defaultPageSize = 10, className, }) {
|
|
8
|
+
const [sorting, setSorting] = useState([]);
|
|
9
|
+
const [columnVisibility, setColumnVisibility] = useState({});
|
|
10
|
+
const [rowSelection, setRowSelection] = useState({});
|
|
11
|
+
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: defaultPageSize });
|
|
12
|
+
const table = useReactTable({
|
|
13
|
+
data,
|
|
14
|
+
columns,
|
|
15
|
+
getCoreRowModel: getCoreRowModel(),
|
|
16
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
17
|
+
getSortedRowModel: getSortedRowModel(),
|
|
18
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
19
|
+
onSortingChange: setSorting,
|
|
20
|
+
onColumnVisibilityChange: setColumnVisibility,
|
|
21
|
+
onRowSelectionChange: setRowSelection,
|
|
22
|
+
onPaginationChange: setPagination,
|
|
23
|
+
state: { sorting, columnVisibility, rowSelection, pagination },
|
|
24
|
+
});
|
|
25
|
+
const totalRows = table.getFilteredRowModel().rows.length;
|
|
26
|
+
const { pageIndex, pageSize } = table.getState().pagination;
|
|
27
|
+
const from = totalRows === 0 ? 0 : pageIndex * pageSize + 1;
|
|
28
|
+
const to = Math.min((pageIndex + 1) * pageSize, totalRows);
|
|
29
|
+
return (_jsxs("div", { className: cn('rounded-xl border border-border bg-card overflow-hidden', className), children: [(title || description) && (_jsxs("div", { className: "px-6 py-4 border-b border-border", children: [title && _jsx("h2", { className: "text-lg font-semibold text-foreground", children: title }), description && _jsx("p", { className: "text-sm text-muted-foreground mt-0.5", children: description })] })), _jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { children: table.getHeaderGroups().map((headerGroup) => (_jsx("tr", { className: "border-b border-border bg-muted/40", children: headerGroup.headers.map((header) => {
|
|
30
|
+
const canSort = header.column.getCanSort();
|
|
31
|
+
const sorted = header.column.getIsSorted();
|
|
32
|
+
return (_jsx("th", { className: cn('px-4 py-3 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider select-none whitespace-nowrap', canSort && 'cursor-pointer hover:text-foreground transition-colors'), onClick: canSort ? header.column.getToggleSortingHandler() : undefined, children: _jsxs("div", { className: "flex items-center gap-1.5", children: [header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()), canSort && (_jsx("span", { className: "ml-0.5 text-muted-foreground/60", children: sorted === 'asc' ? (_jsx(ArrowUp, { className: "w-3 h-3 text-primary" })) : sorted === 'desc' ? (_jsx(ArrowDown, { className: "w-3 h-3 text-primary" })) : (_jsx(ArrowUpDown, { className: "w-3 h-3" })) }))] }) }, header.id));
|
|
33
|
+
}) }, headerGroup.id))) }), _jsx("tbody", { children: table.getRowModel().rows.length === 0 ? (_jsx("tr", { children: _jsx("td", { colSpan: columns.length, className: "px-6 py-12 text-center text-muted-foreground/50 text-sm", children: "No data to display" }) })) : (table.getRowModel().rows.map((row) => (_jsx("tr", { className: cn('border-b border-border/50 transition-colors hover:bg-muted/30 last:border-0', row.getIsSelected() && 'bg-primary/5'), children: row.getVisibleCells().map((cell) => (_jsx("td", { className: "px-4 py-3 text-foreground align-middle", children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))) }, row.id)))) })] }) }), _jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between px-4 py-3 border-t border-border bg-muted/20", children: [_jsx("p", { className: "text-xs text-muted-foreground text-center sm:text-left", children: totalRows === 0
|
|
34
|
+
? 'No results'
|
|
35
|
+
: `Showing ${from}–${to} of ${totalRows} row${totalRows !== 1 ? 's' : ''}` }), _jsxs("div", { className: "flex items-center gap-3 justify-center", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-xs text-muted-foreground whitespace-nowrap", children: "Rows" }), _jsx("select", { value: pageSize, onChange: (e) => table.setPageSize(Number(e.target.value)), className: "h-7 rounded-md border border-input bg-background px-2 text-xs focus:outline-none focus:ring-1 focus:ring-ring", children: pageSizeOptions.map((s) => (_jsx("option", { value: s, children: s }, s))) })] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { onClick: () => table.setPageIndex(0), disabled: !table.getCanPreviousPage(), className: "p-1 rounded hover:bg-muted transition-colors disabled:opacity-30 disabled:cursor-not-allowed", title: "First page", children: _jsx(ChevronsLeft, { className: "w-4 h-4" }) }), _jsx("button", { onClick: () => table.previousPage(), disabled: !table.getCanPreviousPage(), className: "p-1 rounded hover:bg-muted transition-colors disabled:opacity-30 disabled:cursor-not-allowed", title: "Previous page", children: _jsx(ChevronLeft, { className: "w-4 h-4" }) }), _jsxs("span", { className: "text-xs text-muted-foreground px-2 whitespace-nowrap", children: [pageIndex + 1, " / ", table.getPageCount() || 1] }), _jsx("button", { onClick: () => table.nextPage(), disabled: !table.getCanNextPage(), className: "p-1 rounded hover:bg-muted transition-colors disabled:opacity-30 disabled:cursor-not-allowed", title: "Next page", children: _jsx(ChevronRight, { className: "w-4 h-4" }) }), _jsx("button", { onClick: () => table.setPageIndex(table.getPageCount() - 1), disabled: !table.getCanNextPage(), className: "p-1 rounded hover:bg-muted transition-colors disabled:opacity-30 disabled:cursor-not-allowed", title: "Last page", children: _jsx(ChevronsRight, { className: "w-4 h-4" }) })] })] })] })] }));
|
|
36
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface EmptyStateProps {
|
|
3
|
+
/** Lucide icon element or any ReactNode to show above the title */
|
|
4
|
+
icon?: React.ReactNode;
|
|
5
|
+
/** Image src as alternative to icon */
|
|
6
|
+
imageSrc?: string;
|
|
7
|
+
/** Main heading */
|
|
8
|
+
title: string;
|
|
9
|
+
/** Supporting text */
|
|
10
|
+
description: string;
|
|
11
|
+
/** Label for the primary CTA button */
|
|
12
|
+
actionLabel?: string;
|
|
13
|
+
/** If provided, CTA renders as a Next.js Link */
|
|
14
|
+
actionHref?: string;
|
|
15
|
+
/** If provided, CTA calls this function (takes precedence over actionHref) */
|
|
16
|
+
onAction?: () => void;
|
|
17
|
+
/** Extra content rendered below the CTA */
|
|
18
|
+
footer?: React.ReactNode;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function EmptyState({ icon, imageSrc, title, description, actionLabel, actionHref, onAction, footer, className, }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=EmptyState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../../../src/components/data/EmptyState.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,UAAU,eAAe;IACvB,mEAAmE;IACnE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,WAAW,EACX,WAA2B,EAC3B,UAAU,EACV,QAAQ,EACR,MAAM,EACN,SAAS,GACV,EAAE,eAAe,2CAgDjB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import { Plus, FolderOpen } from 'lucide-react';
|
|
5
|
+
import { cn } from '../../utils/cn';
|
|
6
|
+
export function EmptyState({ icon, imageSrc, title, description, actionLabel = 'Get Started', actionHref, onAction, footer, className, }) {
|
|
7
|
+
const hasAction = onAction || actionHref;
|
|
8
|
+
return (_jsxs("div", { className: cn('relative flex flex-col items-center justify-center py-16 px-4 text-center overflow-hidden', className), children: [_jsxs("div", { "aria-hidden": true, className: "pointer-events-none absolute inset-0 -z-10", children: [_jsx("div", { className: "absolute top-1/4 left-1/4 w-48 h-48 bg-primary/5 rounded-full blur-3xl" }), _jsx("div", { className: "absolute bottom-1/4 right-1/4 w-48 h-48 bg-primary/5 rounded-full blur-3xl" })] }), imageSrc ? (_jsx("img", { src: imageSrc, alt: title, className: "w-28 h-28 mb-6 opacity-60 object-contain" })) : (_jsx("div", { className: "mb-6 p-5 rounded-2xl bg-muted/70 text-muted-foreground", children: icon ?? _jsx(FolderOpen, { className: "w-10 h-10" }) })), _jsx("h3", { className: "text-xl font-bold text-foreground mb-2", children: title }), _jsx("p", { className: "text-muted-foreground max-w-sm text-sm leading-relaxed mb-7", children: description }), hasAction && (onAction ? (_jsxs("button", { onClick: onAction, className: "inline-flex items-center gap-2 h-10 px-5 rounded-lg bg-primary text-primary-foreground text-sm font-semibold hover:opacity-90 transition-opacity shadow-sm", children: [_jsx(Plus, { className: "w-4 h-4" }), actionLabel] })) : actionHref ? (_jsxs(Link, { href: actionHref, className: "inline-flex items-center gap-2 h-10 px-5 rounded-lg bg-primary text-primary-foreground text-sm font-semibold hover:opacity-90 transition-opacity shadow-sm", children: [_jsx(Plus, { className: "w-4 h-4" }), actionLabel] })) : null), footer && _jsx("div", { className: "mt-4", children: footer })] }));
|
|
9
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface TableToolbarProps {
|
|
2
|
+
searchValue: string;
|
|
3
|
+
onSearchChange: (value: string) => void;
|
|
4
|
+
onExport?: () => void;
|
|
5
|
+
onImport?: () => void;
|
|
6
|
+
selectedCount?: number;
|
|
7
|
+
onBulkDelete?: () => void;
|
|
8
|
+
onBulkArchive?: () => void;
|
|
9
|
+
onColumnSettings?: () => void;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
/** Extra action buttons rendered to the right of search */
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
export declare function TableToolbar({ searchValue, onSearchChange, onExport, onImport, selectedCount, onBulkDelete, onBulkArchive, onColumnSettings, placeholder, className, children, }: TableToolbarProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=TableToolbar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TableToolbar.d.ts","sourceRoot":"","sources":["../../../src/components/data/TableToolbar.tsx"],"names":[],"mappings":"AAUA,UAAU,iBAAiB;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,wBAAgB,YAAY,CAAC,EAC3B,WAAW,EACX,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,aAAiB,EACjB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,WAAyB,EACzB,SAAS,EACT,QAAQ,GACT,EAAE,iBAAiB,2CAyGnB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Input } from '../base/input';
|
|
4
|
+
import { Search, Download, Upload, Settings2, MoreHorizontal, Trash2, Archive, X, } from 'lucide-react';
|
|
5
|
+
import { useState, useRef, useEffect } from 'react';
|
|
6
|
+
import { cn } from '../../utils/cn';
|
|
7
|
+
export function TableToolbar({ searchValue, onSearchChange, onExport, onImport, selectedCount = 0, onBulkDelete, onBulkArchive, onColumnSettings, placeholder = 'Search...', className, children, }) {
|
|
8
|
+
const [showBulkMenu, setShowBulkMenu] = useState(false);
|
|
9
|
+
const bulkRef = useRef(null);
|
|
10
|
+
// Close bulk menu on outside click
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const handler = (e) => {
|
|
13
|
+
if (bulkRef.current && !bulkRef.current.contains(e.target)) {
|
|
14
|
+
setShowBulkMenu(false);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
document.addEventListener('mousedown', handler);
|
|
18
|
+
return () => document.removeEventListener('mousedown', handler);
|
|
19
|
+
}, []);
|
|
20
|
+
return (_jsxs("div", { className: cn('flex flex-col gap-3 md:flex-row md:items-center', className), children: [_jsxs("div", { className: "flex-1 relative min-w-0", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground pointer-events-none" }), _jsx(Input, { type: "text", placeholder: placeholder, value: searchValue, onChange: (e) => onSearchChange(e.target.value), className: "pl-9 pr-8" }), searchValue && (_jsx("button", { onClick: () => onSearchChange(''), className: "absolute right-2.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors", children: _jsx(X, { className: "w-3.5 h-3.5" }) }))] }), _jsxs("div", { className: "flex items-center gap-2 flex-wrap shrink-0", children: [children, onImport && (_jsxs("button", { onClick: onImport, className: "inline-flex items-center gap-1.5 h-9 px-3 rounded-md border border-input bg-background text-xs font-medium text-foreground hover:bg-muted transition-colors", children: [_jsx(Upload, { className: "w-3.5 h-3.5" }), " Import"] })), onExport && (_jsxs("button", { onClick: onExport, className: "inline-flex items-center gap-1.5 h-9 px-3 rounded-md border border-input bg-background text-xs font-medium text-foreground hover:bg-muted transition-colors", children: [_jsx(Download, { className: "w-3.5 h-3.5" }), " Export"] })), onColumnSettings && (_jsx("button", { onClick: onColumnSettings, className: "inline-flex items-center justify-center h-9 w-9 rounded-md border border-input bg-background text-muted-foreground hover:bg-muted transition-colors", title: "Column settings", children: _jsx(Settings2, { className: "w-4 h-4" }) })), selectedCount > 0 && (_jsxs("div", { className: "relative", ref: bulkRef, children: [_jsxs("button", { onClick: () => setShowBulkMenu(!showBulkMenu), className: "inline-flex items-center gap-1.5 h-9 px-3 rounded-md border border-primary/40 bg-primary/5 text-xs font-semibold text-primary hover:bg-primary/10 transition-colors", children: [_jsx(MoreHorizontal, { className: "w-4 h-4" }), selectedCount, " selected"] }), showBulkMenu && (_jsxs("div", { className: "absolute right-0 mt-1 w-44 bg-popover border border-border rounded-lg shadow-lg overflow-hidden z-20 animate-in fade-in-0 zoom-in-95", children: [onBulkArchive && (_jsxs("button", { onClick: () => { onBulkArchive(); setShowBulkMenu(false); }, className: "w-full text-left px-4 py-2.5 text-sm text-muted-foreground hover:bg-muted hover:text-foreground transition-colors flex items-center gap-2", children: [_jsx(Archive, { className: "w-3.5 h-3.5" }), " Archive"] })), onBulkDelete && (_jsxs("button", { onClick: () => { onBulkDelete(); setShowBulkMenu(false); }, className: "w-full text-left px-4 py-2.5 text-sm text-destructive hover:bg-destructive/10 transition-colors flex items-center gap-2 border-t border-border", children: [_jsx(Trash2, { className: "w-3.5 h-3.5" }), " Delete"] }))] }))] }))] })] }));
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface CopyButtonProps {
|
|
2
|
+
/** The text to copy to clipboard */
|
|
3
|
+
value: string;
|
|
4
|
+
/** Milliseconds to show the "Copied!" state. Defaults to 2000 */
|
|
5
|
+
resetMs?: number;
|
|
6
|
+
className?: string;
|
|
7
|
+
/** Render variant. 'icon' shows only the icon. 'button' shows icon + label. */
|
|
8
|
+
variant?: 'icon' | 'button';
|
|
9
|
+
label?: string;
|
|
10
|
+
copiedLabel?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function CopyButton({ value, resetMs, className, variant, label, copiedLabel, }: CopyButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=CopyButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CopyButton.d.ts","sourceRoot":"","sources":["../../../src/components/display/CopyButton.tsx"],"names":[],"mappings":"AAMA,UAAU,eAAe;IACvB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,OAAc,EACd,SAAS,EACT,OAAgB,EAChB,KAAc,EACd,WAAuB,GACxB,EAAE,eAAe,2CA8DjB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useCallback } from 'react';
|
|
4
|
+
import { Copy, Check } from 'lucide-react';
|
|
5
|
+
import { cn } from '../../utils/cn';
|
|
6
|
+
export function CopyButton({ value, resetMs = 2000, className, variant = 'icon', label = 'Copy', copiedLabel = 'Copied!', }) {
|
|
7
|
+
const [copied, setCopied] = useState(false);
|
|
8
|
+
const handleCopy = useCallback(async () => {
|
|
9
|
+
try {
|
|
10
|
+
await navigator.clipboard.writeText(value);
|
|
11
|
+
setCopied(true);
|
|
12
|
+
setTimeout(() => setCopied(false), resetMs);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// Fallback for browsers without clipboard API
|
|
16
|
+
const ta = document.createElement('textarea');
|
|
17
|
+
ta.value = value;
|
|
18
|
+
ta.style.position = 'fixed';
|
|
19
|
+
ta.style.opacity = '0';
|
|
20
|
+
document.body.appendChild(ta);
|
|
21
|
+
ta.focus();
|
|
22
|
+
ta.select();
|
|
23
|
+
document.execCommand('copy');
|
|
24
|
+
document.body.removeChild(ta);
|
|
25
|
+
setCopied(true);
|
|
26
|
+
setTimeout(() => setCopied(false), resetMs);
|
|
27
|
+
}
|
|
28
|
+
}, [value, resetMs]);
|
|
29
|
+
if (variant === 'button') {
|
|
30
|
+
return (_jsxs("button", { onClick: handleCopy, className: cn('inline-flex items-center gap-1.5 h-8 px-3 rounded-md border border-input bg-background text-xs font-medium transition-colors', copied
|
|
31
|
+
? 'border-emerald-500/40 bg-emerald-50 text-emerald-700'
|
|
32
|
+
: 'text-muted-foreground hover:text-foreground hover:bg-muted', className), title: copied ? copiedLabel : label, children: [copied ? (_jsx(Check, { className: "w-3.5 h-3.5" })) : (_jsx(Copy, { className: "w-3.5 h-3.5" })), copied ? copiedLabel : label] }));
|
|
33
|
+
}
|
|
34
|
+
return (_jsx("button", { onClick: handleCopy, className: cn('inline-flex items-center justify-center w-7 h-7 rounded-md transition-colors', copied
|
|
35
|
+
? 'text-emerald-600'
|
|
36
|
+
: 'text-muted-foreground hover:text-foreground hover:bg-muted', className), title: copied ? copiedLabel : label, children: copied ? _jsx(Check, { className: "w-3.5 h-3.5" }) : _jsx(Copy, { className: "w-3.5 h-3.5" }) }));
|
|
37
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
interface PageHeaderProps {
|
|
3
|
+
title: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
/** Right-side action buttons/badges */
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function PageHeader({ title, description, children, className }: PageHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=PageHeader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/display/PageHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,eAAe,2CActF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../../utils/cn';
|
|
3
|
+
export function PageHeader({ title, description, children, className }) {
|
|
4
|
+
return (_jsxs("div", { className: cn('flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between', className), children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h1", { className: "text-2xl sm:text-3xl font-bold tracking-tight text-foreground truncate", children: title }), description && (_jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: description }))] }), children && (_jsx("div", { className: "flex items-center gap-2 flex-wrap shrink-0", children: children }))] }));
|
|
5
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
interface TrendProps {
|
|
3
|
+
value: number;
|
|
4
|
+
label?: string;
|
|
5
|
+
}
|
|
6
|
+
interface StatCardProps {
|
|
7
|
+
/** Lucide icon or any icon node */
|
|
8
|
+
icon?: React.ReactNode;
|
|
9
|
+
/** Primary numeric value to display */
|
|
10
|
+
value: string | number;
|
|
11
|
+
/** Metric label */
|
|
12
|
+
label: string;
|
|
13
|
+
/** Optional trend indicator */
|
|
14
|
+
trend?: TrendProps;
|
|
15
|
+
/** Optional sub-label below value */
|
|
16
|
+
subLabel?: string;
|
|
17
|
+
/** Icon background color class (Tailwind). Defaults to bg-primary/10 */
|
|
18
|
+
iconColor?: string;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function StatCard({ icon, value, label, trend, subLabel, iconColor, className, }: StatCardProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=StatCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatCard.d.ts","sourceRoot":"","sources":["../../../src/components/display/StatCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,aAAa;IACrB,mCAAmC;IACnC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,uCAAuC;IACvC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,KAAK,EACL,KAAK,EACL,KAAK,EACL,QAAQ,EACR,SAAwC,EACxC,SAAS,GACV,EAAE,aAAa,2CA2Cf"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../../utils/cn';
|
|
3
|
+
export function StatCard({ icon, value, label, trend, subLabel, iconColor = 'bg-primary/10 text-primary', className, }) {
|
|
4
|
+
const trendUp = trend && trend.value >= 0;
|
|
5
|
+
return (_jsxs("div", { className: cn('group relative rounded-2xl border border-border bg-card p-5 overflow-hidden transition-shadow hover:shadow-md', className), children: [_jsx("div", { "aria-hidden": true, className: "pointer-events-none absolute inset-0 rounded-2xl opacity-0 group-hover:opacity-100 transition-opacity bg-gradient-to-br from-primary/5 to-transparent" }), _jsxs("div", { className: "flex items-start justify-between gap-3 relative", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("p", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2", children: label }), _jsx("p", { className: "text-2xl sm:text-3xl font-bold text-foreground tabular-nums", children: value }), subLabel && _jsx("p", { className: "text-xs text-muted-foreground mt-1", children: subLabel }), trend && (_jsxs("div", { className: "flex items-center gap-1 mt-2", children: [_jsxs("span", { className: cn('text-xs font-semibold', trendUp ? 'text-emerald-600' : 'text-red-500'), children: [trendUp ? '+' : '', trend.value.toFixed(1), "%"] }), trend.label && (_jsx("span", { className: "text-xs text-muted-foreground", children: trend.label }))] }))] }), icon && (_jsx("div", { className: cn('w-11 h-11 rounded-xl flex items-center justify-center shrink-0', iconColor), children: icon }))] })] }));
|
|
6
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface ConfirmDialogProps {
|
|
2
|
+
open: boolean;
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
confirmLabel?: string;
|
|
6
|
+
cancelLabel?: string;
|
|
7
|
+
/** When true, the confirm button renders in destructive red */
|
|
8
|
+
isDangerous?: boolean;
|
|
9
|
+
/** Called when user confirms */
|
|
10
|
+
onConfirm: () => void;
|
|
11
|
+
/** Called when user cancels or closes */
|
|
12
|
+
onCancel: () => void;
|
|
13
|
+
/** Show a loading spinner on the confirm button */
|
|
14
|
+
isLoading?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function ConfirmDialog({ open, title, description, confirmLabel, cancelLabel, isDangerous, onConfirm, onCancel, isLoading, }: ConfirmDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=ConfirmDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmDialog.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/ConfirmDialog.tsx"],"names":[],"mappings":"AAOA,UAAU,kBAAkB;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gCAAgC;IAChC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,mDAAmD;IACnD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,WAAW,EACX,YAAwB,EACxB,WAAsB,EACtB,WAAmB,EACnB,SAAS,EACT,QAAQ,EACR,SAAiB,GAClB,EAAE,kBAAkB,2CAuDpB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
4
|
+
import { AlertCircle } from 'lucide-react';
|
|
5
|
+
import { cn } from '../../utils/cn';
|
|
6
|
+
export function ConfirmDialog({ open, title, description, confirmLabel = 'Confirm', cancelLabel = 'Cancel', isDangerous = false, onConfirm, onCancel, isLoading = false, }) {
|
|
7
|
+
return (_jsx(DialogPrimitive.Root, { open: open, onOpenChange: (isOpen) => !isOpen && onCancel(), children: _jsxs(DialogPrimitive.Portal, { children: [_jsx(DialogPrimitive.Overlay, { className: "fixed inset-0 z-50 bg-black/60 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" }), _jsxs(DialogPrimitive.Content, { className: "fixed left-1/2 top-1/2 z-50 w-full max-w-sm -translate-x-1/2 -translate-y-1/2 rounded-2xl border border-border bg-card p-6 shadow-2xl data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", children: [_jsxs("div", { className: "flex items-start gap-3 mb-3", children: [isDangerous && (_jsx("div", { className: "w-10 h-10 rounded-full bg-destructive/10 flex items-center justify-center shrink-0 mt-0.5", children: _jsx(AlertCircle, { className: "w-5 h-5 text-destructive" }) })), _jsxs("div", { className: "flex-1", children: [_jsx(DialogPrimitive.Title, { className: "text-base font-semibold text-foreground leading-tight", children: title }), _jsx(DialogPrimitive.Description, { className: "mt-1.5 text-sm text-muted-foreground leading-relaxed", children: description })] })] }), _jsxs("div", { className: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end mt-5", children: [_jsx("button", { onClick: onCancel, disabled: isLoading, className: "inline-flex items-center justify-center h-9 px-4 rounded-lg border border-input bg-background text-sm font-medium text-foreground hover:bg-muted transition-colors disabled:opacity-50", children: cancelLabel }), _jsxs("button", { onClick: onConfirm, disabled: isLoading, className: cn('inline-flex items-center justify-center gap-2 h-9 px-4 rounded-lg text-sm font-semibold text-white transition-colors disabled:opacity-50', isDangerous
|
|
8
|
+
? 'bg-destructive hover:bg-destructive/90'
|
|
9
|
+
: 'bg-primary hover:bg-primary/90'), children: [isLoading && (_jsxs("svg", { className: "w-4 h-4 animate-spin", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v8H4z" })] })), confirmLabel] })] })] })] }) }));
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface ErrorStateProps {
|
|
2
|
+
/** The error message to display */
|
|
3
|
+
error: string;
|
|
4
|
+
/** Optional retry callback */
|
|
5
|
+
onRetry?: () => void;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function ErrorState({ error, onRetry, className }: ErrorStateProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=ErrorState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorState.d.ts","sourceRoot":"","sources":["../../../src/components/feedback/ErrorState.tsx"],"names":[],"mappings":"AAKA,UAAU,eAAe;IACvB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,eAAe,2CAoBxE"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { AlertTriangle, RefreshCw } from 'lucide-react';
|
|
4
|
+
import { cn } from '../../utils/cn';
|
|
5
|
+
export function ErrorState({ error, onRetry, className }) {
|
|
6
|
+
return (_jsxs("div", { className: cn('flex flex-col items-center justify-center py-16 gap-4 text-center', className), children: [_jsx("div", { className: "w-14 h-14 rounded-full bg-destructive/10 flex items-center justify-center", children: _jsx(AlertTriangle, { className: "w-6 h-6 text-destructive" }) }), _jsxs("div", { children: [_jsx("p", { className: "font-semibold text-foreground", children: "Something went wrong" }), _jsx("p", { className: "text-sm text-muted-foreground mt-1 max-w-sm", children: error })] }), onRetry && (_jsxs("button", { onClick: onRetry, className: "inline-flex items-center gap-2 h-8 px-4 rounded-md border border-input bg-background text-xs font-medium text-foreground hover:bg-muted transition-colors", children: [_jsx(RefreshCw, { className: "w-3.5 h-3.5" }), " Try Again"] }))] }));
|
|
7
|
+
}
|