@checkstack/ui 0.4.1 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @checkstack/ui
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 223081d: Add icon support to PageLayout and improve mobile responsiveness
8
+
9
+ **PageLayout Icons:**
10
+
11
+ - Added required `icon` prop to `PageLayout` and `PageHeader` components that accepts a Lucide icon component reference
12
+ - Icons are rendered with consistent `h-6 w-6 text-primary` styling
13
+ - Updated all page components to include appropriate icons in their headers
14
+
15
+ **Mobile Layout Improvements:**
16
+
17
+ - Standardized responsive padding in main app shell (`p-3` on mobile, `p-6` on desktop)
18
+ - Added `CardHeaderRow` component for mobile-safe card headers with proper wrapping
19
+ - Improved `DateRangeFilter` responsive behavior with vertical stacking on mobile
20
+ - Migrated pages to use `PageLayout` for consistent responsive behavior
21
+
3
22
  ## 0.4.1
4
23
 
5
24
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/ui",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "dependencies": {
@@ -8,7 +8,7 @@ export const Card = ({
8
8
  <div
9
9
  className={cn(
10
10
  "rounded-lg border border-border bg-card text-card-foreground shadow-sm",
11
- className
11
+ className,
12
12
  )}
13
13
  {...props}
14
14
  />
@@ -21,6 +21,23 @@ export const CardHeader = ({
21
21
  <div className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} />
22
22
  );
23
23
 
24
+ /**
25
+ * A row layout for card headers with title and actions.
26
+ * Provides mobile-friendly defaults with flex-wrap and gap.
27
+ */
28
+ export const CardHeaderRow = ({
29
+ className,
30
+ ...props
31
+ }: React.HTMLAttributes<HTMLDivElement>) => (
32
+ <div
33
+ className={cn(
34
+ "flex flex-wrap items-center justify-between gap-3",
35
+ className,
36
+ )}
37
+ {...props}
38
+ />
39
+ );
40
+
24
41
  export const CardTitle = ({
25
42
  className,
26
43
  ...props
@@ -28,7 +45,7 @@ export const CardTitle = ({
28
45
  <h3
29
46
  className={cn(
30
47
  "text-2xl font-semibold leading-none tracking-tight",
31
- className
48
+ className,
32
49
  )}
33
50
  {...props}
34
51
  />
@@ -22,11 +22,15 @@ export interface DateRangeFilterProps {
22
22
  className?: string;
23
23
  }
24
24
 
25
- const PRESETS: Array<{ id: DateRangePreset; label: string }> = [
26
- { id: DateRangePreset.Last24Hours, label: "Last 24h" },
27
- { id: DateRangePreset.Last7Days, label: "Last 7 days" },
28
- { id: DateRangePreset.Last30Days, label: "Last 30 days" },
29
- { id: DateRangePreset.Custom, label: "Custom" },
25
+ const PRESETS: Array<{
26
+ id: DateRangePreset;
27
+ label: string;
28
+ shortLabel: string;
29
+ }> = [
30
+ { id: DateRangePreset.Last24Hours, label: "Last 24h", shortLabel: "24h" },
31
+ { id: DateRangePreset.Last7Days, label: "Last 7 days", shortLabel: "7d" },
32
+ { id: DateRangePreset.Last30Days, label: "Last 30 days", shortLabel: "30d" },
33
+ { id: DateRangePreset.Custom, label: "Custom", shortLabel: "Custom" },
30
34
  ];
31
35
 
32
36
  export function getPresetRange(preset: DateRangePreset): DateRange {
@@ -88,7 +92,7 @@ export const DateRangeFilter: React.FC<DateRangeFilterProps> = ({
88
92
  <span className="text-sm font-medium text-muted-foreground">
89
93
  Time range:
90
94
  </span>
91
- <div className="flex gap-1">
95
+ <div className="flex gap-1 flex-wrap">
92
96
  {PRESETS.map((preset) => (
93
97
  <Button
94
98
  key={preset.id}
@@ -102,7 +106,8 @@ export const DateRangeFilter: React.FC<DateRangeFilterProps> = ({
102
106
  size="sm"
103
107
  onClick={() => handlePresetClick(preset.id)}
104
108
  >
105
- {preset.label}
109
+ <span className="sm:hidden">{preset.shortLabel}</span>
110
+ <span className="hidden sm:inline">{preset.label}</span>
106
111
  </Button>
107
112
  ))}
108
113
  </div>
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+ import type { LucideIcon } from "lucide-react";
2
3
  import { cn } from "../utils";
3
4
 
4
5
  interface PageProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -14,33 +15,37 @@ export const Page = React.forwardRef<HTMLDivElement, PageProps>(
14
15
  >
15
16
  {children}
16
17
  </div>
17
- )
18
+ ),
18
19
  );
19
20
  Page.displayName = "Page";
20
21
 
21
22
  interface PageHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
22
23
  title: string;
23
24
  subtitle?: string;
25
+ icon: LucideIcon;
24
26
  actions?: React.ReactNode;
25
27
  }
26
28
 
27
29
  export const PageHeader = React.forwardRef<HTMLDivElement, PageHeaderProps>(
28
- ({ className, title, subtitle, actions, ...props }, ref) => (
30
+ ({ className, title, subtitle, icon: Icon, actions, ...props }, ref) => (
29
31
  <div
30
32
  ref={ref}
31
33
  className={cn(
32
- "flex flex-col md:flex-row items-center justify-between p-6 pb-2",
33
- className
34
+ "flex flex-col md:flex-row items-center justify-between py-3 pb-2 md:py-6 md:pb-2",
35
+ className,
34
36
  )}
35
37
  {...props}
36
38
  >
37
39
  <div className="space-y-1">
38
- <h2 className="text-2xl font-bold tracking-tight">{title}</h2>
40
+ <div className="flex items-center gap-3">
41
+ <Icon className="h-6 w-6 text-primary" />
42
+ <h2 className="text-2xl font-bold tracking-tight">{title}</h2>
43
+ </div>
39
44
  {subtitle && <p className="text-muted-foreground">{subtitle}</p>}
40
45
  </div>
41
46
  {actions && <div className="flex items-center space-x-2">{actions}</div>}
42
47
  </div>
43
- )
48
+ ),
44
49
  );
45
50
  PageHeader.displayName = "PageHeader";
46
51
 
@@ -50,9 +55,13 @@ interface PageContentProps extends React.HTMLAttributes<HTMLDivElement> {
50
55
 
51
56
  export const PageContent = React.forwardRef<HTMLDivElement, PageContentProps>(
52
57
  ({ className, children, ...props }, ref) => (
53
- <div ref={ref} className={cn("flex-1 p-6 pt-2", className)} {...props}>
58
+ <div
59
+ ref={ref}
60
+ className={cn("flex-1 py-3 pt-2 md:py-6 md:pt-2", className)}
61
+ {...props}
62
+ >
54
63
  {children}
55
64
  </div>
56
- )
65
+ ),
57
66
  );
58
67
  PageContent.displayName = "PageContent";
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+ import type { LucideIcon } from "lucide-react";
2
3
  import {
3
4
  Page,
4
5
  PageHeader,
@@ -10,6 +11,7 @@ import {
10
11
  interface PageLayoutProps {
11
12
  title: string;
12
13
  subtitle?: string;
14
+ icon: LucideIcon;
13
15
  actions?: React.ReactNode;
14
16
  loading?: boolean;
15
17
  allowed?: boolean;
@@ -31,6 +33,7 @@ interface PageLayoutProps {
31
33
  export const PageLayout: React.FC<PageLayoutProps> = ({
32
34
  title,
33
35
  subtitle,
36
+ icon,
34
37
  actions,
35
38
  loading,
36
39
  allowed,
@@ -46,7 +49,12 @@ export const PageLayout: React.FC<PageLayoutProps> = ({
46
49
  if (isLoading) {
47
50
  return (
48
51
  <Page>
49
- <PageHeader title={title} subtitle={subtitle} actions={actions} />
52
+ <PageHeader
53
+ title={title}
54
+ subtitle={subtitle}
55
+ icon={icon}
56
+ actions={actions}
57
+ />
50
58
  <PageContent>
51
59
  <div className="flex justify-center py-12">
52
60
  <LoadingSpinner />
@@ -60,7 +68,12 @@ export const PageLayout: React.FC<PageLayoutProps> = ({
60
68
  if (allowed === false) {
61
69
  return (
62
70
  <Page>
63
- <PageHeader title={title} subtitle={subtitle} actions={actions} />
71
+ <PageHeader
72
+ title={title}
73
+ subtitle={subtitle}
74
+ icon={icon}
75
+ actions={actions}
76
+ />
64
77
  <PageContent>
65
78
  <AccessDenied />
66
79
  </PageContent>
@@ -70,10 +83,17 @@ export const PageLayout: React.FC<PageLayoutProps> = ({
70
83
 
71
84
  return (
72
85
  <Page>
73
- <PageHeader title={title} subtitle={subtitle} actions={actions} />
86
+ <PageHeader
87
+ title={title}
88
+ subtitle={subtitle}
89
+ icon={icon}
90
+ actions={actions}
91
+ />
74
92
  <PageContent>
75
93
  <div
76
- className={maxWidth === "full" ? "" : `max-w-${maxWidth} space-y-6`}
94
+ className={
95
+ maxWidth === "full" ? "space-y-6" : `max-w-${maxWidth} space-y-6`
96
+ }
77
97
  >
78
98
  {children}
79
99
  </div>