@flamingo-stack/openframe-frontend-core 0.0.253 → 0.0.254
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/dist/{chunk-E7LM7TPK.cjs → chunk-65JN25VM.cjs} +25 -25
- package/dist/{chunk-E7LM7TPK.cjs.map → chunk-65JN25VM.cjs.map} +1 -1
- package/dist/{chunk-N37WSTB7.js → chunk-BE472J6X.js} +2 -2
- package/dist/{chunk-4WFV4OTE.js → chunk-CAPVFI5A.js} +2 -2
- package/dist/{chunk-TNC2OENX.cjs → chunk-HYJ5IV4Z.cjs} +11 -11
- package/dist/{chunk-TNC2OENX.cjs.map → chunk-HYJ5IV4Z.cjs.map} +1 -1
- package/dist/{chunk-IA6B3HHQ.js → chunk-NP5U35FA.js} +53 -29
- package/dist/chunk-NP5U35FA.js.map +1 -0
- package/dist/{chunk-AXCLUHMQ.js → chunk-QCRQNKRO.js} +2 -2
- package/dist/{chunk-YEWZVXKX.cjs → chunk-TSY72CQ6.cjs} +28 -28
- package/dist/{chunk-YEWZVXKX.cjs.map → chunk-TSY72CQ6.cjs.map} +1 -1
- package/dist/{chunk-44UP5DJB.cjs → chunk-ZITMX2IQ.cjs} +53 -29
- package/dist/chunk-ZITMX2IQ.cjs.map +1 -0
- package/dist/components/chat/index.cjs +2 -2
- package/dist/components/chat/index.js +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/index.cjs +49 -49
- package/dist/components/index.js +3 -3
- package/dist/components/navigation/index.cjs +2 -2
- package/dist/components/navigation/index.js +1 -1
- package/dist/components/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/tickets/index.cjs +55 -55
- package/dist/components/tickets/index.js +3 -3
- package/dist/components/ui/index.cjs +2 -2
- package/dist/components/ui/index.js +1 -1
- package/dist/components/ui/info-card.d.ts +16 -1
- package/dist/components/ui/info-card.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/ui/info-card.tsx +87 -42
- package/src/stories/InfoCard.stories.tsx +60 -5
- package/dist/chunk-44UP5DJB.cjs.map +0 -1
- package/dist/chunk-IA6B3HHQ.js.map +0 -1
- /package/dist/{chunk-N37WSTB7.js.map → chunk-BE472J6X.js.map} +0 -0
- /package/dist/{chunk-4WFV4OTE.js.map → chunk-CAPVFI5A.js.map} +0 -0
- /package/dist/{chunk-AXCLUHMQ.js.map → chunk-QCRQNKRO.js.map} +0 -0
|
@@ -7,7 +7,21 @@ import { CheckIcon } from '../icons-v2-generated'
|
|
|
7
7
|
import { useCopyToClipboard } from '../../hooks'
|
|
8
8
|
import { ProgressBar } from './progress-bar'
|
|
9
9
|
|
|
10
|
-
interface
|
|
10
|
+
export interface InfoCardFooterData {
|
|
11
|
+
/** Leading icon next to the text, expected at 24x24 (e.g. <ShieldCheckIcon size={24} />) */
|
|
12
|
+
icon?: React.ReactNode
|
|
13
|
+
text: string
|
|
14
|
+
/** Trailing icon/logo aligned to the right edge, expected at 24x24 */
|
|
15
|
+
logo?: React.ReactNode
|
|
16
|
+
/** External resource link rendered below the text row */
|
|
17
|
+
link?: {
|
|
18
|
+
href: string
|
|
19
|
+
/** Defaults to href without the protocol */
|
|
20
|
+
label?: string
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface InfoCardData {
|
|
11
25
|
title?: string
|
|
12
26
|
subtitle?: string
|
|
13
27
|
icon?: React.ReactNode
|
|
@@ -22,6 +36,8 @@ interface InfoCardData {
|
|
|
22
36
|
criticalThreshold?: number
|
|
23
37
|
inverted?: boolean // if true, high values are good (green), low values are bad (red)
|
|
24
38
|
}
|
|
39
|
+
/** Optional footer rendered below the content, separated by a divider line */
|
|
40
|
+
footer?: InfoCardFooterData
|
|
25
41
|
}
|
|
26
42
|
|
|
27
43
|
interface InfoCardProps {
|
|
@@ -33,54 +49,83 @@ export function InfoCard({ data, className = '' }: InfoCardProps) {
|
|
|
33
49
|
return (
|
|
34
50
|
<div
|
|
35
51
|
className={cn(
|
|
36
|
-
'bg-ods-card border border-ods-border rounded-md
|
|
52
|
+
'bg-ods-card border border-ods-border rounded-md overflow-hidden flex flex-col w-full',
|
|
37
53
|
className,
|
|
38
54
|
)}
|
|
39
55
|
>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<
|
|
43
|
-
{data.title}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
56
|
+
<div className="p-[var(--spacing-system-m)] flex flex-col gap-[var(--spacing-system-s)] items-start w-full">
|
|
57
|
+
{data.title && (
|
|
58
|
+
<div className="flex items-center gap-[var(--spacing-system-xsf)] self-stretch h-6">
|
|
59
|
+
<span className="text-h4 text-ods-text-primary truncate" title={data.title}>
|
|
60
|
+
{data.title}
|
|
61
|
+
</span>
|
|
62
|
+
{data.icon}
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
48
65
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
66
|
+
{/* Subtitle */}
|
|
67
|
+
{data.subtitle && (
|
|
68
|
+
<div className="text-h4 text-ods-text-secondary truncate self-stretch" title={data.subtitle}>
|
|
69
|
+
{data.subtitle}
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
55
72
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
73
|
+
{/* Info items */}
|
|
74
|
+
{data.items.map((item, index) => {
|
|
75
|
+
const values = Array.isArray(item.value) ? item.value : [item.value]
|
|
59
76
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
return (
|
|
78
|
+
<React.Fragment key={index}>
|
|
79
|
+
{values.map((val, valIndex) => (
|
|
80
|
+
<InfoCardValueRow
|
|
81
|
+
key={`${index}-${valIndex}`}
|
|
82
|
+
label={item.label}
|
|
83
|
+
value={val}
|
|
84
|
+
showLabel={valIndex === 0}
|
|
85
|
+
copyable={item.copyable}
|
|
86
|
+
copyAriaLabel={`Copy ${item.label ?? 'value'} ${valIndex + 1}`}
|
|
87
|
+
/>
|
|
88
|
+
))}
|
|
89
|
+
</React.Fragment>
|
|
90
|
+
)
|
|
91
|
+
})}
|
|
75
92
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
93
|
+
{/* Progress bar */}
|
|
94
|
+
{data.progress && (
|
|
95
|
+
<ProgressBar
|
|
96
|
+
progress={data.progress.value}
|
|
97
|
+
warningThreshold={data.progress.warningThreshold}
|
|
98
|
+
criticalThreshold={data.progress.criticalThreshold}
|
|
99
|
+
inverted={data.progress.inverted}
|
|
100
|
+
/>
|
|
101
|
+
)}
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
{/* Footer */}
|
|
105
|
+
{data.footer && <InfoCardFooter footer={data.footer} />}
|
|
106
|
+
</div>
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function InfoCardFooter({ footer }: { footer: InfoCardFooterData }) {
|
|
111
|
+
return (
|
|
112
|
+
<div className="mt-auto border-t border-ods-border p-[var(--spacing-system-m)] flex flex-col w-full">
|
|
113
|
+
<div className="flex items-center justify-between gap-1 w-full">
|
|
114
|
+
<div className="flex items-center gap-1">
|
|
115
|
+
{footer.icon}
|
|
116
|
+
<span className="text-h4 text-ods-text-primary">{footer.text}</span>
|
|
117
|
+
</div>
|
|
118
|
+
{footer.logo}
|
|
119
|
+
</div>
|
|
120
|
+
{footer.link && (
|
|
121
|
+
<a
|
|
122
|
+
href={footer.link.href}
|
|
123
|
+
target="_blank"
|
|
124
|
+
rel="noopener noreferrer"
|
|
125
|
+
className="text-h6 text-ods-text-secondary underline truncate hover:text-ods-text-primary"
|
|
126
|
+
>
|
|
127
|
+
{footer.link.label ?? footer.link.href.replace(/^https?:\/\//, '')}
|
|
128
|
+
</a>
|
|
84
129
|
)}
|
|
85
130
|
</div>
|
|
86
131
|
)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
|
|
2
2
|
import { InfoCard } from '../components'
|
|
3
|
+
import { ShieldCheckIcon } from '../components/icons-v2-generated/security'
|
|
4
|
+
import { FlamingoLogo } from '../components/icons'
|
|
3
5
|
|
|
4
6
|
const meta = {
|
|
5
7
|
title: 'UI/InfoCard',
|
|
@@ -9,7 +11,7 @@ const meta = {
|
|
|
9
11
|
docs: {
|
|
10
12
|
description: {
|
|
11
13
|
component:
|
|
12
|
-
'A dark-themed info card showing a title, optional subtitle, label/value rows with dotted leaders, optional copy buttons, and an optional
|
|
14
|
+
'A dark-themed info card showing a title, optional subtitle, label/value rows with dotted leaders, optional copy buttons, an optional progress bar, and an optional footer with an icon, text, trailing logo, and external link, separated by a divider line.',
|
|
13
15
|
},
|
|
14
16
|
},
|
|
15
17
|
},
|
|
@@ -32,7 +34,7 @@ export const DiskC: Story = {
|
|
|
32
34
|
},
|
|
33
35
|
},
|
|
34
36
|
render: (args) => (
|
|
35
|
-
<div
|
|
37
|
+
<div className="w-80">
|
|
36
38
|
<InfoCard {...args} />
|
|
37
39
|
</div>
|
|
38
40
|
),
|
|
@@ -51,7 +53,7 @@ export const DiskD: Story = {
|
|
|
51
53
|
},
|
|
52
54
|
},
|
|
53
55
|
render: (args) => (
|
|
54
|
-
<div
|
|
56
|
+
<div className="w-80">
|
|
55
57
|
<InfoCard {...args} />
|
|
56
58
|
</div>
|
|
57
59
|
),
|
|
@@ -70,7 +72,7 @@ export const PhysicalRAM: Story = {
|
|
|
70
72
|
},
|
|
71
73
|
},
|
|
72
74
|
render: (args) => (
|
|
73
|
-
<div
|
|
75
|
+
<div className="w-80">
|
|
74
76
|
<InfoCard {...args} />
|
|
75
77
|
</div>
|
|
76
78
|
),
|
|
@@ -86,10 +88,63 @@ export const WithCopyableValues: Story = {
|
|
|
86
88
|
{ label: 'IPv4', value: '192.168.1.100', copyable: true },
|
|
87
89
|
{ label: 'MAC', value: '00:1A:2B:3C:4D:5E', copyable: true },
|
|
88
90
|
],
|
|
91
|
+
footer: {
|
|
92
|
+
icon: <ShieldCheckIcon size={24} className="text-ods-success" />,
|
|
93
|
+
text: 'Signed by Flamingo',
|
|
94
|
+
logo: <FlamingoLogo width={24} height={24} />,
|
|
95
|
+
link: { href: 'https://github.com/flamingo-ai/fleetdm' },
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
render: (args) => (
|
|
100
|
+
<div className="w-96">
|
|
101
|
+
<InfoCard {...args} />
|
|
102
|
+
</div>
|
|
103
|
+
),
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const WithFooter: Story = {
|
|
107
|
+
args: {
|
|
108
|
+
data: {
|
|
109
|
+
title: 'Fleet',
|
|
110
|
+
items: [
|
|
111
|
+
{ label: 'Status', value: 'ONLINE' },
|
|
112
|
+
{ label: 'Last seen', value: '06/11/26 9:35 AM' },
|
|
113
|
+
{ label: 'ID', value: '7', copyable: true },
|
|
114
|
+
{ label: 'Version', value: '0.1.8' },
|
|
115
|
+
],
|
|
116
|
+
footer: {
|
|
117
|
+
icon: <ShieldCheckIcon size={24} className="text-ods-success" />,
|
|
118
|
+
text: 'Signed by Flamingo',
|
|
119
|
+
logo: <FlamingoLogo width={24} height={24} />,
|
|
120
|
+
link: { href: 'https://github.com/flamingo-ai/fleetdm' },
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
render: (args) => (
|
|
125
|
+
<div className="w-96">
|
|
126
|
+
<InfoCard {...args} />
|
|
127
|
+
</div>
|
|
128
|
+
),
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export const WithFooterWithoutLink: Story = {
|
|
132
|
+
args: {
|
|
133
|
+
data: {
|
|
134
|
+
title: 'Fleet',
|
|
135
|
+
items: [
|
|
136
|
+
{ label: 'Status', value: 'ONLINE' },
|
|
137
|
+
{ label: 'Version', value: '0.1.8' },
|
|
138
|
+
],
|
|
139
|
+
footer: {
|
|
140
|
+
icon: <ShieldCheckIcon size={24} className="text-ods-success" />,
|
|
141
|
+
text: 'Signed by Flamingo',
|
|
142
|
+
logo: <FlamingoLogo width={24} height={24} />,
|
|
143
|
+
},
|
|
89
144
|
},
|
|
90
145
|
},
|
|
91
146
|
render: (args) => (
|
|
92
|
-
<div
|
|
147
|
+
<div className="w-96">
|
|
93
148
|
<InfoCard {...args} />
|
|
94
149
|
</div>
|
|
95
150
|
),
|