@shipfox/react-ui 0.14.0 → 0.15.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/.storybook/preview.tsx +7 -0
- package/.turbo/turbo-build.log +7 -7
- package/.turbo/turbo-check.log +2 -2
- package/.turbo/turbo-type.log +1 -1
- package/CHANGELOG.md +10 -0
- package/dist/components/avatar/avatar.js +1 -1
- package/dist/components/avatar/avatar.js.map +1 -1
- package/dist/components/button-group/button-group.d.ts +17 -0
- package/dist/components/button-group/button-group.d.ts.map +1 -0
- package/dist/components/button-group/button-group.js +74 -0
- package/dist/components/button-group/button-group.js.map +1 -0
- package/dist/components/button-group/button-group.stories.js +644 -0
- package/dist/components/button-group/button-group.stories.js.map +1 -0
- package/dist/components/button-group/index.d.ts +2 -0
- package/dist/components/button-group/index.d.ts.map +1 -0
- package/dist/components/button-group/index.js +3 -0
- package/dist/components/button-group/index.js.map +1 -0
- package/dist/components/code-block/code-block-footer.d.ts.map +1 -1
- package/dist/components/code-block/code-block-footer.js +4 -2
- package/dist/components/code-block/code-block-footer.js.map +1 -1
- package/dist/components/command/command.d.ts +28 -0
- package/dist/components/command/command.d.ts.map +1 -0
- package/dist/components/command/command.js +190 -0
- package/dist/components/command/command.js.map +1 -0
- package/dist/components/command/command.stories.js +228 -0
- package/dist/components/command/command.stories.js.map +1 -0
- package/dist/components/command/index.d.ts +2 -0
- package/dist/components/command/index.d.ts.map +1 -0
- package/dist/components/command/index.js +3 -0
- package/dist/components/command/index.js.map +1 -0
- package/dist/components/dashboard/components/analytics-content.d.ts +2 -0
- package/dist/components/dashboard/components/analytics-content.d.ts.map +1 -0
- package/dist/components/dashboard/components/analytics-content.js +180 -0
- package/dist/components/dashboard/components/analytics-content.js.map +1 -0
- package/dist/components/dashboard/components/animated-logo.d.ts +4 -0
- package/dist/components/dashboard/components/animated-logo.d.ts.map +1 -0
- package/dist/components/dashboard/components/animated-logo.js +23 -0
- package/dist/components/dashboard/components/animated-logo.js.map +1 -0
- package/dist/components/dashboard/components/complete-setup-button.d.ts +4 -0
- package/dist/components/dashboard/components/complete-setup-button.d.ts.map +1 -0
- package/dist/components/dashboard/components/complete-setup-button.js +28 -0
- package/dist/components/dashboard/components/complete-setup-button.js.map +1 -0
- package/dist/components/dashboard/components/jobs-content.d.ts +2 -0
- package/dist/components/dashboard/components/jobs-content.d.ts.map +1 -0
- package/dist/components/dashboard/components/jobs-content.js +69 -0
- package/dist/components/dashboard/components/jobs-content.js.map +1 -0
- package/dist/components/dashboard/components/mobile-menu.d.ts +2 -0
- package/dist/components/dashboard/components/mobile-menu.d.ts.map +1 -0
- package/dist/components/dashboard/components/mobile-menu.js +65 -0
- package/dist/components/dashboard/components/mobile-menu.js.map +1 -0
- package/dist/components/dashboard/components/organization-selector.d.ts +2 -0
- package/dist/components/dashboard/components/organization-selector.d.ts.map +1 -0
- package/dist/components/dashboard/components/organization-selector.js +92 -0
- package/dist/components/dashboard/components/organization-selector.js.map +1 -0
- package/dist/components/dashboard/components/top-menu.d.ts +5 -0
- package/dist/components/dashboard/components/top-menu.d.ts.map +1 -0
- package/dist/components/dashboard/components/top-menu.js +31 -0
- package/dist/components/dashboard/components/top-menu.js.map +1 -0
- package/dist/components/dashboard/components/topbar-button.d.ts +7 -0
- package/dist/components/dashboard/components/topbar-button.d.ts.map +1 -0
- package/dist/components/dashboard/components/topbar-button.js +18 -0
- package/dist/components/dashboard/components/topbar-button.js.map +1 -0
- package/dist/components/dashboard/components/topbar.d.ts +4 -0
- package/dist/components/dashboard/components/topbar.d.ts.map +1 -0
- package/dist/components/dashboard/components/topbar.js +62 -0
- package/dist/components/dashboard/components/topbar.js.map +1 -0
- package/dist/components/dashboard/components/user-profile.d.ts +2 -0
- package/dist/components/dashboard/components/user-profile.d.ts.map +1 -0
- package/dist/components/dashboard/components/user-profile.js +146 -0
- package/dist/components/dashboard/components/user-profile.js.map +1 -0
- package/dist/components/dashboard/dashboard.d.ts +2 -0
- package/dist/components/dashboard/dashboard.d.ts.map +1 -0
- package/dist/components/dashboard/dashboard.js +70 -0
- package/dist/components/dashboard/dashboard.js.map +1 -0
- package/dist/components/dashboard/dashboard.stories.js +23 -0
- package/dist/components/dashboard/dashboard.stories.js.map +1 -0
- package/dist/components/dashboard/index.d.ts +2 -0
- package/dist/components/dashboard/index.d.ts.map +1 -0
- package/dist/components/dashboard/index.js +3 -0
- package/dist/components/dashboard/index.js.map +1 -0
- package/dist/components/form/form.stories.js +6 -1
- package/dist/components/form/form.stories.js.map +1 -1
- package/dist/components/index.d.ts +7 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +7 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/kbd/index.d.ts +2 -0
- package/dist/components/kbd/index.d.ts.map +1 -0
- package/dist/components/kbd/index.js +3 -0
- package/dist/components/kbd/index.js.map +1 -0
- package/dist/components/kbd/kbd.d.ts +7 -0
- package/dist/components/kbd/kbd.d.ts.map +1 -0
- package/dist/components/kbd/kbd.js +18 -0
- package/dist/components/kbd/kbd.js.map +1 -0
- package/dist/components/kbd/kbd.stories.js +119 -0
- package/dist/components/kbd/kbd.stories.js.map +1 -0
- package/dist/components/search/index.d.ts +7 -0
- package/dist/components/search/index.d.ts.map +1 -0
- package/dist/components/search/index.js +8 -0
- package/dist/components/search/index.js.map +1 -0
- package/dist/components/search/search-context.d.ts +11 -0
- package/dist/components/search/search-context.d.ts.map +1 -0
- package/dist/components/search/search-context.js +56 -0
- package/dist/components/search/search-context.js.map +1 -0
- package/dist/components/search/search-inline.d.ts +9 -0
- package/dist/components/search/search-inline.d.ts.map +1 -0
- package/dist/components/search/search-inline.js +85 -0
- package/dist/components/search/search-inline.js.map +1 -0
- package/dist/components/search/search-modal.d.ts +25 -0
- package/dist/components/search/search-modal.d.ts.map +1 -0
- package/dist/components/search/search-modal.js +162 -0
- package/dist/components/search/search-modal.js.map +1 -0
- package/dist/components/search/search-trigger.d.ts +9 -0
- package/dist/components/search/search-trigger.d.ts.map +1 -0
- package/dist/components/search/search-trigger.js +37 -0
- package/dist/components/search/search-trigger.js.map +1 -0
- package/dist/components/search/search-variants.d.ts +14 -0
- package/dist/components/search/search-variants.d.ts.map +1 -0
- package/dist/components/search/search-variants.js +90 -0
- package/dist/components/search/search-variants.js.map +1 -0
- package/dist/components/search/search.d.ts +11 -0
- package/dist/components/search/search.d.ts.map +1 -0
- package/dist/components/search/search.js +35 -0
- package/dist/components/search/search.js.map +1 -0
- package/dist/components/search/search.stories.js +630 -0
- package/dist/components/search/search.stories.js.map +1 -0
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/select/index.d.ts.map +1 -0
- package/dist/components/select/index.js +3 -0
- package/dist/components/select/index.js.map +1 -0
- package/dist/components/select/select.d.ts +25 -0
- package/dist/components/select/select.d.ts.map +1 -0
- package/dist/components/select/select.js +153 -0
- package/dist/components/select/select.js.map +1 -0
- package/dist/components/select/select.stories.js +393 -0
- package/dist/components/select/select.stories.js.map +1 -0
- package/dist/components/skeleton/index.d.ts +2 -0
- package/dist/components/skeleton/index.d.ts.map +1 -0
- package/dist/components/skeleton/index.js +3 -0
- package/dist/components/skeleton/index.js.map +1 -0
- package/dist/components/skeleton/skeleton.d.ts +5 -0
- package/dist/components/skeleton/skeleton.d.ts.map +1 -0
- package/dist/components/skeleton/skeleton.js +11 -0
- package/dist/components/skeleton/skeleton.js.map +1 -0
- package/dist/components/skeleton/skeleton.stories.js +345 -0
- package/dist/components/skeleton/skeleton.stories.js.map +1 -0
- package/dist/components/table/data-table.d.ts +70 -0
- package/dist/components/table/data-table.d.ts.map +1 -0
- package/dist/components/table/data-table.js +159 -0
- package/dist/components/table/data-table.js.map +1 -0
- package/dist/components/table/index.d.ts +6 -0
- package/dist/components/table/index.d.ts.map +1 -0
- package/dist/components/table/index.js +6 -0
- package/dist/components/table/index.js.map +1 -0
- package/dist/components/table/table-column-header.d.ts +79 -0
- package/dist/components/table/table-column-header.d.ts.map +1 -0
- package/dist/components/table/table-column-header.js +99 -0
- package/dist/components/table/table-column-header.js.map +1 -0
- package/dist/components/table/table-pagination.d.ts +53 -0
- package/dist/components/table/table-pagination.d.ts.map +1 -0
- package/dist/components/table/table-pagination.js +139 -0
- package/dist/components/table/table-pagination.js.map +1 -0
- package/dist/components/table/table.d.ts +11 -0
- package/dist/components/table/table.d.ts.map +1 -0
- package/dist/components/table/table.js +64 -0
- package/dist/components/table/table.js.map +1 -0
- package/dist/components/table/table.stories.columns.d.ts +24 -0
- package/dist/components/table/table.stories.columns.d.ts.map +1 -0
- package/dist/components/table/table.stories.columns.js +310 -0
- package/dist/components/table/table.stories.columns.js.map +1 -0
- package/dist/components/table/table.stories.components.d.ts +14 -0
- package/dist/components/table/table.stories.components.d.ts.map +1 -0
- package/dist/components/table/table.stories.components.js +107 -0
- package/dist/components/table/table.stories.components.js.map +1 -0
- package/dist/components/table/table.stories.data.d.ts +54 -0
- package/dist/components/table/table.stories.data.d.ts.map +1 -0
- package/dist/components/table/table.stories.data.js +122 -0
- package/dist/components/table/table.stories.data.js.map +1 -0
- package/dist/components/table/table.stories.js +302 -0
- package/dist/components/table/table.stories.js.map +1 -0
- package/dist/styles.css +1 -1
- package/index.css +48 -0
- package/package.json +3 -2
- package/src/components/avatar/avatar.tsx +1 -1
- package/src/components/button-group/button-group.stories.tsx +361 -0
- package/src/components/button-group/button-group.tsx +111 -0
- package/src/components/button-group/index.ts +1 -0
- package/src/components/code-block/code-block-footer.tsx +8 -1
- package/src/components/command/command.stories.tsx +133 -0
- package/src/components/command/command.tsx +265 -0
- package/src/components/command/index.ts +1 -0
- package/src/components/dashboard/components/analytics-content.tsx +102 -0
- package/src/components/dashboard/components/animated-logo.tsx +25 -0
- package/src/components/dashboard/components/complete-setup-button.tsx +30 -0
- package/src/components/dashboard/components/jobs-content.tsx +51 -0
- package/src/components/dashboard/components/mobile-menu.tsx +50 -0
- package/src/components/dashboard/components/organization-selector.tsx +51 -0
- package/src/components/dashboard/components/top-menu.tsx +26 -0
- package/src/components/dashboard/components/topbar-button.tsx +27 -0
- package/src/components/dashboard/components/topbar.tsx +40 -0
- package/src/components/dashboard/components/user-profile.tsx +90 -0
- package/src/components/dashboard/dashboard.stories.tsx +25 -0
- package/src/components/dashboard/dashboard.tsx +61 -0
- package/src/components/dashboard/index.ts +1 -0
- package/src/components/form/form.stories.tsx +5 -0
- package/src/components/index.ts +7 -0
- package/src/components/kbd/index.ts +1 -0
- package/src/components/kbd/kbd.stories.tsx +64 -0
- package/src/components/kbd/kbd.tsx +32 -0
- package/src/components/search/index.ts +28 -0
- package/src/components/search/search-context.tsx +78 -0
- package/src/components/search/search-inline.tsx +107 -0
- package/src/components/search/search-modal.tsx +198 -0
- package/src/components/search/search-trigger.tsx +47 -0
- package/src/components/search/search-variants.ts +88 -0
- package/src/components/search/search.stories.tsx +392 -0
- package/src/components/search/search.tsx +47 -0
- package/src/components/select/index.ts +1 -0
- package/src/components/select/select.stories.tsx +207 -0
- package/src/components/select/select.tsx +220 -0
- package/src/components/skeleton/index.ts +1 -0
- package/src/components/skeleton/skeleton.stories.tsx +178 -0
- package/src/components/skeleton/skeleton.tsx +14 -0
- package/src/components/table/data-table.tsx +254 -0
- package/src/components/table/index.ts +5 -0
- package/src/components/table/table-column-header.tsx +141 -0
- package/src/components/table/table-pagination.tsx +161 -0
- package/src/components/table/table.stories.columns.tsx +198 -0
- package/src/components/table/table.stories.components.tsx +104 -0
- package/src/components/table/table.stories.data.ts +117 -0
- package/src/components/table/table.stories.tsx +256 -0
- package/src/components/table/table.tsx +95 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import {cva, type VariantProps} from 'class-variance-authority';
|
|
2
|
+
import {Command as CommandPrimitive} from 'cmdk';
|
|
3
|
+
import {type ComponentProps, forwardRef, useCallback, useState} from 'react';
|
|
4
|
+
import {cn} from 'utils/cn';
|
|
5
|
+
import {Icon} from '../icon';
|
|
6
|
+
import {Kbd} from '../kbd';
|
|
7
|
+
|
|
8
|
+
const commandTriggerVariants = cva(
|
|
9
|
+
[
|
|
10
|
+
'flex items-center justify-between gap-8',
|
|
11
|
+
'w-full rounded-6 px-8 text-sm leading-20',
|
|
12
|
+
'bg-background-field-base text-foreground-neutral-base',
|
|
13
|
+
'shadow-button-neutral transition-[color,box-shadow] outline-none',
|
|
14
|
+
'hover:bg-background-field-hover cursor-pointer',
|
|
15
|
+
'focus-visible:shadow-border-interactive-with-active',
|
|
16
|
+
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-background-neutral-disabled disabled:shadow-none disabled:text-foreground-neutral-disabled',
|
|
17
|
+
],
|
|
18
|
+
{
|
|
19
|
+
variants: {
|
|
20
|
+
variant: {
|
|
21
|
+
base: 'bg-background-field-base',
|
|
22
|
+
component: 'bg-background-field-component',
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
small: 'h-28 py-4',
|
|
26
|
+
base: 'h-32 py-6',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
variant: 'base',
|
|
31
|
+
size: 'base',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
type CommandTriggerProps = ComponentProps<'button'> &
|
|
37
|
+
VariantProps<typeof commandTriggerVariants> & {
|
|
38
|
+
placeholder?: string;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const CommandTrigger = forwardRef<HTMLButtonElement, CommandTriggerProps>(
|
|
42
|
+
({className, variant, size, placeholder, children, ...props}, ref) => {
|
|
43
|
+
const hasValue = Boolean(children);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<button
|
|
47
|
+
ref={ref}
|
|
48
|
+
type="button"
|
|
49
|
+
data-slot="command-trigger"
|
|
50
|
+
data-placeholder={!hasValue || undefined}
|
|
51
|
+
className={cn(
|
|
52
|
+
commandTriggerVariants({variant, size}),
|
|
53
|
+
'data-placeholder:text-foreground-neutral-muted',
|
|
54
|
+
className,
|
|
55
|
+
)}
|
|
56
|
+
{...props}
|
|
57
|
+
>
|
|
58
|
+
<span className="flex-1 text-left truncate">{hasValue ? children : placeholder}</span>
|
|
59
|
+
<Icon name="arrowDownSLine" className="size-16 text-foreground-neutral-muted shrink-0" />
|
|
60
|
+
</button>
|
|
61
|
+
);
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
CommandTrigger.displayName = 'CommandTrigger';
|
|
65
|
+
|
|
66
|
+
function Command({className, ...props}: ComponentProps<typeof CommandPrimitive>) {
|
|
67
|
+
return (
|
|
68
|
+
<CommandPrimitive
|
|
69
|
+
data-slot="command"
|
|
70
|
+
className={cn(
|
|
71
|
+
'flex h-full w-full flex-col overflow-hidden rounded-10',
|
|
72
|
+
'bg-background-neutral-overlay text-foreground-neutral-base',
|
|
73
|
+
className,
|
|
74
|
+
)}
|
|
75
|
+
{...props}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function CommandDialog({children, ...props}: ComponentProps<typeof CommandPrimitive.Dialog>) {
|
|
81
|
+
return (
|
|
82
|
+
<CommandPrimitive.Dialog data-slot="command-dialog" {...props}>
|
|
83
|
+
<div className="fixed inset-0 z-50 bg-background-neutral-overlay/80 backdrop-blur-sm" />
|
|
84
|
+
<div className="fixed left-1/2 top-1/2 z-50 w-full max-w-600 -translate-x-1/2 -translate-y-1/2 p-16">
|
|
85
|
+
<Command className="shadow-tooltip">{children}</Command>
|
|
86
|
+
</div>
|
|
87
|
+
</CommandPrimitive.Dialog>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
type CommandInputProps = ComponentProps<typeof CommandPrimitive.Input> & {
|
|
92
|
+
showClearButton?: boolean;
|
|
93
|
+
onClear?: () => void;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
function CommandInput({
|
|
97
|
+
className,
|
|
98
|
+
value,
|
|
99
|
+
onValueChange,
|
|
100
|
+
onClear,
|
|
101
|
+
showClearButton = true,
|
|
102
|
+
...props
|
|
103
|
+
}: CommandInputProps) {
|
|
104
|
+
const [internalValue, setInternalValue] = useState('');
|
|
105
|
+
const isControlled = value !== undefined;
|
|
106
|
+
const inputValue = isControlled ? value : internalValue;
|
|
107
|
+
const hasValue = Boolean(inputValue);
|
|
108
|
+
|
|
109
|
+
const handleValueChange = useCallback(
|
|
110
|
+
(newValue: string) => {
|
|
111
|
+
if (!isControlled) {
|
|
112
|
+
setInternalValue(newValue);
|
|
113
|
+
}
|
|
114
|
+
onValueChange?.(newValue);
|
|
115
|
+
},
|
|
116
|
+
[isControlled, onValueChange],
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const handleClear = useCallback(() => {
|
|
120
|
+
if (!isControlled) {
|
|
121
|
+
setInternalValue('');
|
|
122
|
+
}
|
|
123
|
+
onValueChange?.('');
|
|
124
|
+
onClear?.();
|
|
125
|
+
}, [isControlled, onValueChange, onClear]);
|
|
126
|
+
|
|
127
|
+
const handleKeyDown = useCallback(
|
|
128
|
+
(e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
129
|
+
if (e.key === 'Escape' && hasValue) {
|
|
130
|
+
e.preventDefault();
|
|
131
|
+
e.stopPropagation();
|
|
132
|
+
handleClear();
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
[hasValue, handleClear],
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<div className="flex items-center gap-8 border-b border-border-neutral-strong p-8">
|
|
140
|
+
<Icon name="searchLine" className="size-16 shrink-0 text-foreground-neutral-muted" />
|
|
141
|
+
<CommandPrimitive.Input
|
|
142
|
+
data-slot="command-input"
|
|
143
|
+
value={inputValue}
|
|
144
|
+
onValueChange={handleValueChange}
|
|
145
|
+
onKeyDown={handleKeyDown}
|
|
146
|
+
className={cn(
|
|
147
|
+
'flex-1 bg-transparent text-sm leading-20 outline-none',
|
|
148
|
+
'placeholder:text-foreground-neutral-muted',
|
|
149
|
+
'disabled:cursor-not-allowed disabled:text-foreground-neutral-disabled',
|
|
150
|
+
className,
|
|
151
|
+
)}
|
|
152
|
+
{...props}
|
|
153
|
+
/>
|
|
154
|
+
{showClearButton && hasValue && (
|
|
155
|
+
<button
|
|
156
|
+
type="button"
|
|
157
|
+
onClick={handleClear}
|
|
158
|
+
className={cn(
|
|
159
|
+
'shrink-0 cursor-pointer rounded-4 p-2',
|
|
160
|
+
'text-foreground-neutral-muted hover:text-foreground-neutral-subtle transition-colors',
|
|
161
|
+
)}
|
|
162
|
+
aria-label="Clear search"
|
|
163
|
+
>
|
|
164
|
+
<Icon name="closeLine" className="size-16" />
|
|
165
|
+
</button>
|
|
166
|
+
)}
|
|
167
|
+
</div>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function CommandList({className, ...props}: ComponentProps<typeof CommandPrimitive.List>) {
|
|
172
|
+
return (
|
|
173
|
+
<CommandPrimitive.List
|
|
174
|
+
data-slot="command-list"
|
|
175
|
+
className={cn('max-h-300 overflow-y-auto overflow-x-hidden p-4 scrollbar', className)}
|
|
176
|
+
{...props}
|
|
177
|
+
/>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function CommandEmpty({className, ...props}: ComponentProps<typeof CommandPrimitive.Empty>) {
|
|
182
|
+
return (
|
|
183
|
+
<CommandPrimitive.Empty
|
|
184
|
+
data-slot="command-empty"
|
|
185
|
+
className={cn('py-24 text-center text-sm text-foreground-neutral-muted', className)}
|
|
186
|
+
{...props}
|
|
187
|
+
/>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function CommandGroup({className, ...props}: ComponentProps<typeof CommandPrimitive.Group>) {
|
|
192
|
+
return (
|
|
193
|
+
<CommandPrimitive.Group
|
|
194
|
+
data-slot="command-group"
|
|
195
|
+
className={cn(
|
|
196
|
+
'overflow-hidden',
|
|
197
|
+
'[&_[cmdk-group-heading]]:px-8 [&_[cmdk-group-heading]]:py-4',
|
|
198
|
+
'[&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:leading-20',
|
|
199
|
+
'[&_[cmdk-group-heading]]:text-foreground-neutral-subtle',
|
|
200
|
+
'[&_[cmdk-group-heading]]:select-none',
|
|
201
|
+
className,
|
|
202
|
+
)}
|
|
203
|
+
{...props}
|
|
204
|
+
/>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function CommandSeparator({
|
|
209
|
+
className,
|
|
210
|
+
...props
|
|
211
|
+
}: ComponentProps<typeof CommandPrimitive.Separator>) {
|
|
212
|
+
return (
|
|
213
|
+
<CommandPrimitive.Separator
|
|
214
|
+
data-slot="command-separator"
|
|
215
|
+
className={cn(
|
|
216
|
+
'relative -mx-4 my-4 h-px',
|
|
217
|
+
'bg-border-neutral-menu-top',
|
|
218
|
+
'after:absolute after:inset-x-0 after:top-px after:h-px',
|
|
219
|
+
'after:bg-border-neutral-menu-bottom',
|
|
220
|
+
className,
|
|
221
|
+
)}
|
|
222
|
+
{...props}
|
|
223
|
+
/>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function CommandItem({className, ...props}: ComponentProps<typeof CommandPrimitive.Item>) {
|
|
228
|
+
return (
|
|
229
|
+
<CommandPrimitive.Item
|
|
230
|
+
data-slot="command-item"
|
|
231
|
+
className={cn(
|
|
232
|
+
'relative flex cursor-pointer select-none items-center gap-8 rounded-6 px-8 py-6',
|
|
233
|
+
'text-sm leading-20 text-foreground-neutral-subtle outline-none transition-colors',
|
|
234
|
+
'aria-selected:bg-background-components-hover aria-selected:text-foreground-neutral-base',
|
|
235
|
+
'data-[disabled=true]:pointer-events-none data-[disabled=true]:text-foreground-neutral-disabled',
|
|
236
|
+
className,
|
|
237
|
+
)}
|
|
238
|
+
{...props}
|
|
239
|
+
/>
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function CommandShortcut({className, children, ...props}: ComponentProps<typeof Kbd>) {
|
|
244
|
+
return (
|
|
245
|
+
<Kbd data-slot="command-shortcut" className={cn('ml-auto', className)} {...props}>
|
|
246
|
+
{children}
|
|
247
|
+
</Kbd>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export {
|
|
252
|
+
Command,
|
|
253
|
+
CommandTrigger,
|
|
254
|
+
CommandDialog,
|
|
255
|
+
CommandInput,
|
|
256
|
+
CommandList,
|
|
257
|
+
CommandEmpty,
|
|
258
|
+
CommandGroup,
|
|
259
|
+
CommandItem,
|
|
260
|
+
CommandSeparator,
|
|
261
|
+
CommandShortcut,
|
|
262
|
+
commandTriggerVariants,
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
export type {CommandTriggerProps, CommandInputProps};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './command';
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {Icon} from 'components/icon';
|
|
2
|
+
import {Skeleton} from 'components/skeleton';
|
|
3
|
+
import {Text} from 'components/typography';
|
|
4
|
+
|
|
5
|
+
export function AnalyticsContent() {
|
|
6
|
+
return (
|
|
7
|
+
<div className="min-h-[calc(100vh-48px)] p-12 md:p-24 space-y-16 md:space-y-20 bg-background-neutral-base">
|
|
8
|
+
<div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-12 md:gap-0">
|
|
9
|
+
<Skeleton className="h-28 md:h-32 w-120 md:w-160" />
|
|
10
|
+
<div className="flex items-center gap-8 md:gap-16">
|
|
11
|
+
<Skeleton className="h-28 md:h-32 w-80 md:w-100" />
|
|
12
|
+
<Skeleton className="h-28 md:h-32 w-100 md:w-160" />
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div className="flex gap-12 md:gap-16 overflow-x-auto scrollbar pb-4 md:pb-0 -mx-12 px-12 md:mx-0 md:px-0">
|
|
17
|
+
{['Total', 'Success', 'Failed', 'Neutral', 'Failure rate'].map((label) => (
|
|
18
|
+
<div
|
|
19
|
+
key={label}
|
|
20
|
+
className="shrink-0 w-100 md:w-auto md:flex-1 p-12 rounded-8 bg-background-neutral-base border border-border-neutral-base"
|
|
21
|
+
>
|
|
22
|
+
<p className="text-xs text-foreground-neutral-subtle mb-4">{label}</p>
|
|
23
|
+
<Skeleton className="h-20 w-40" />
|
|
24
|
+
</div>
|
|
25
|
+
))}
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div className="flex flex-col md:flex-row gap-16 md:gap-20">
|
|
29
|
+
<div className="flex-1 p-12 rounded-8 bg-background-neutral-base border border-border-neutral-base">
|
|
30
|
+
<p className="text-sm font-medium text-foreground-neutral-base mb-12">
|
|
31
|
+
Performance over time
|
|
32
|
+
</p>
|
|
33
|
+
<div className="h-120 md:h-160 flex items-center justify-center">
|
|
34
|
+
<div className="text-center">
|
|
35
|
+
<Icon
|
|
36
|
+
name="fileChartLine"
|
|
37
|
+
className="size-24 text-foreground-neutral-muted mx-auto mb-8"
|
|
38
|
+
/>
|
|
39
|
+
<p className="text-sm text-foreground-neutral-subtle">Nothing here yet.</p>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<div className="flex-1 p-12 rounded-8 bg-background-neutral-base border border-border-neutral-base">
|
|
44
|
+
<p className="text-sm font-medium text-foreground-neutral-base mb-12">
|
|
45
|
+
Duration distribution
|
|
46
|
+
</p>
|
|
47
|
+
<div className="h-120 md:h-160 flex items-center justify-center">
|
|
48
|
+
<div className="text-center">
|
|
49
|
+
<Icon
|
|
50
|
+
name="barChartBoxLine"
|
|
51
|
+
className="size-24 text-foreground-neutral-muted mx-auto mb-8"
|
|
52
|
+
/>
|
|
53
|
+
<p className="text-sm text-foreground-neutral-subtle">Nothing here yet.</p>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div className="rounded-8 bg-background-neutral-base border border-border-neutral-base overflow-hidden">
|
|
60
|
+
<div className="flex flex-col md:flex-row items-start md:items-center justify-between p-12 gap-12 md:gap-0 border-b border-border-neutral-strong">
|
|
61
|
+
<p className="text-sm font-medium text-foreground-neutral-base">Jobs breakdown</p>
|
|
62
|
+
<div className="flex items-center gap-8 md:gap-16 w-full md:w-auto">
|
|
63
|
+
<Skeleton className="h-28 flex-1 md:flex-none md:w-200" />
|
|
64
|
+
<Skeleton className="h-28 w-28 shrink-0" />
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
<div className="py-48 md:py-64 flex flex-col items-center justify-center gap-12">
|
|
68
|
+
<div className="size-32 rounded-6 bg-transparent border border-border-neutral-strong flex items-center justify-center">
|
|
69
|
+
<Icon
|
|
70
|
+
name="shipfox"
|
|
71
|
+
className="size-16 text-foreground-neutral-subtle"
|
|
72
|
+
color="var(--foreground-neutral-subtle, #a1a1aa)"
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
<div className="text-center space-y-4 px-16">
|
|
76
|
+
<Text size="sm" className="text-foreground-neutral-base">
|
|
77
|
+
No jobs yet
|
|
78
|
+
</Text>
|
|
79
|
+
<Text size="xs" className="text-foreground-neutral-muted">
|
|
80
|
+
Import past runs or start a runner.
|
|
81
|
+
</Text>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div className="space-y-16">
|
|
87
|
+
{Array.from({length: 3}).map((_, i) => {
|
|
88
|
+
const blockId = `analytics-extra-block-${i}`;
|
|
89
|
+
return (
|
|
90
|
+
<div
|
|
91
|
+
key={blockId}
|
|
92
|
+
className="p-12 md:p-16 rounded-8 bg-background-subtle-base border border-border-neutral-strong"
|
|
93
|
+
>
|
|
94
|
+
<Skeleton className="h-16 w-full max-w-400 mb-8" />
|
|
95
|
+
<Skeleton className="h-12 w-full max-w-600" />
|
|
96
|
+
</div>
|
|
97
|
+
);
|
|
98
|
+
})}
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {Icon} from 'components/icon';
|
|
2
|
+
import {motion} from 'framer-motion';
|
|
3
|
+
|
|
4
|
+
const LOGO_HEIGHT = 48;
|
|
5
|
+
|
|
6
|
+
export function AnimatedLogo({scrollProgress}: {scrollProgress: number}) {
|
|
7
|
+
const isVisible = scrollProgress > 0;
|
|
8
|
+
|
|
9
|
+
if (!isVisible) return null;
|
|
10
|
+
|
|
11
|
+
const easedProgress = 1 - (1 - scrollProgress) ** 3;
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<motion.div
|
|
15
|
+
className="fixed top-0 left-0 z-50 flex items-center justify-center shrink-0 w-48 h-48 bg-background-neutral-base"
|
|
16
|
+
style={{
|
|
17
|
+
opacity: easedProgress,
|
|
18
|
+
transform: `translateY(${-LOGO_HEIGHT + easedProgress * LOGO_HEIGHT}px)`,
|
|
19
|
+
}}
|
|
20
|
+
initial={false}
|
|
21
|
+
>
|
|
22
|
+
<Icon name="shipfox" className="size-20 text-foreground-neutral-subtle" />
|
|
23
|
+
</motion.div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {Button} from 'components/button';
|
|
2
|
+
import {ShinyText} from 'components/shiny-text';
|
|
3
|
+
import {useResolvedTheme} from 'hooks/useResolvedTheme';
|
|
4
|
+
import {ShipfoxLoader} from 'shipfox-loader-react';
|
|
5
|
+
import {cn} from 'utils/cn';
|
|
6
|
+
|
|
7
|
+
export function CompleteSetupButton({className}: {className?: string}) {
|
|
8
|
+
const resolvedTheme = useResolvedTheme();
|
|
9
|
+
return (
|
|
10
|
+
<Button
|
|
11
|
+
type="button"
|
|
12
|
+
variant="transparent"
|
|
13
|
+
className={cn(
|
|
14
|
+
'flex items-center gap-8 min-w-124 max-w-280 overflow-hidden px-12 py-10 transition-colors rounded-none h-40 border-l border-border-neutral-strong',
|
|
15
|
+
className,
|
|
16
|
+
)}
|
|
17
|
+
>
|
|
18
|
+
<ShipfoxLoader
|
|
19
|
+
size={13}
|
|
20
|
+
animation="circular"
|
|
21
|
+
color={resolvedTheme === 'dark' ? 'white' : 'orange'}
|
|
22
|
+
background={resolvedTheme === 'dark' ? 'dark' : 'light'}
|
|
23
|
+
/>
|
|
24
|
+
<ShinyText
|
|
25
|
+
text="Complete setup"
|
|
26
|
+
className="flex-1 text-sm font-medium leading-20 text-foreground-neutral-base truncate text-left"
|
|
27
|
+
/>
|
|
28
|
+
</Button>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {Button} from 'components/button';
|
|
2
|
+
import {Icon} from 'components/icon';
|
|
3
|
+
import {SearchInline} from 'components/search/search-inline';
|
|
4
|
+
import {DataTable} from 'components/table/data-table';
|
|
5
|
+
import {jobColumns} from 'components/table/table.stories.columns';
|
|
6
|
+
import {jobsData} from 'components/table/table.stories.data';
|
|
7
|
+
import {Header as TypographyHeader} from 'components/typography';
|
|
8
|
+
import {useMemo, useState} from 'react';
|
|
9
|
+
|
|
10
|
+
export function JobsContent() {
|
|
11
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
12
|
+
|
|
13
|
+
const filteredData = useMemo(
|
|
14
|
+
() => jobsData.filter((job) => job.name.toLowerCase().includes(searchQuery.toLowerCase())),
|
|
15
|
+
[searchQuery],
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div className="min-h-[calc(100vh-48px)] p-12 md:p-24 bg-background-neutral-base">
|
|
20
|
+
<div className="rounded-t-8 overflow-hidden">
|
|
21
|
+
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-12 md:gap-0 p-12 border-t border-x border-border-neutral-base rounded-t-8 bg-background-neutral-base">
|
|
22
|
+
<TypographyHeader variant="h3" className="text-foreground-neutral-base">
|
|
23
|
+
Jobs breakdown
|
|
24
|
+
</TypographyHeader>
|
|
25
|
+
|
|
26
|
+
<div className="flex items-center gap-8 md:gap-16 w-full md:w-auto">
|
|
27
|
+
<SearchInline
|
|
28
|
+
placeholder="Search..."
|
|
29
|
+
value={searchQuery}
|
|
30
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
31
|
+
onClear={() => setSearchQuery('')}
|
|
32
|
+
className="flex-1 md:w-240"
|
|
33
|
+
/>
|
|
34
|
+
<Button variant="secondary" aria-label="Insert column left" className="shrink-0">
|
|
35
|
+
<Icon name="insertColumnLeft" className="size-16 text-foreground-neutral-subtle" />
|
|
36
|
+
</Button>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<DataTable
|
|
41
|
+
columns={jobColumns}
|
|
42
|
+
data={filteredData}
|
|
43
|
+
pagination={true}
|
|
44
|
+
pageSize={10}
|
|
45
|
+
pageSizeOptions={[10, 20, 50, 100]}
|
|
46
|
+
className="rounded-t-none"
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {Button} from 'components/button';
|
|
2
|
+
import {
|
|
3
|
+
DropdownMenu,
|
|
4
|
+
DropdownMenuContent,
|
|
5
|
+
DropdownMenuItem,
|
|
6
|
+
DropdownMenuSeparator,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
} from 'components/dropdown-menu';
|
|
9
|
+
import {Icon} from 'components/icon';
|
|
10
|
+
import {ShinyText} from 'components/shiny-text';
|
|
11
|
+
import {useResolvedTheme} from 'hooks/useResolvedTheme';
|
|
12
|
+
import {ShipfoxLoader} from 'shipfox-loader-react';
|
|
13
|
+
|
|
14
|
+
export function MobileMenu() {
|
|
15
|
+
const resolvedTheme = useResolvedTheme();
|
|
16
|
+
return (
|
|
17
|
+
<DropdownMenu>
|
|
18
|
+
<DropdownMenuTrigger asChild>
|
|
19
|
+
<Button
|
|
20
|
+
type="button"
|
|
21
|
+
variant="transparent"
|
|
22
|
+
className="flex md:hidden items-center justify-center shrink-0 w-40 h-40 bg-background-subtle-base hover:bg-background-neutral-hover transition-colors rounded-none border-l border-border-neutral-strong"
|
|
23
|
+
aria-label="Menu"
|
|
24
|
+
>
|
|
25
|
+
<Icon name="menuLine" className="size-18 text-foreground-neutral-subtle" />
|
|
26
|
+
</Button>
|
|
27
|
+
</DropdownMenuTrigger>
|
|
28
|
+
<DropdownMenuContent align="end" className="w-200">
|
|
29
|
+
<DropdownMenuItem>
|
|
30
|
+
<div className="flex items-center gap-8">
|
|
31
|
+
<ShipfoxLoader
|
|
32
|
+
size={13}
|
|
33
|
+
animation="circular"
|
|
34
|
+
color={resolvedTheme === 'dark' ? 'white' : 'orange'}
|
|
35
|
+
background={resolvedTheme === 'dark' ? 'dark' : 'light'}
|
|
36
|
+
/>
|
|
37
|
+
<ShinyText
|
|
38
|
+
text="Complete setup"
|
|
39
|
+
className="flex-1 text-sm font-medium leading-20 text-foreground-neutral-base truncate text-left"
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
</DropdownMenuItem>
|
|
43
|
+
<DropdownMenuSeparator />
|
|
44
|
+
<DropdownMenuItem icon="searchLine">Search</DropdownMenuItem>
|
|
45
|
+
<DropdownMenuItem icon="questionLine">Help</DropdownMenuItem>
|
|
46
|
+
<DropdownMenuItem icon="notification3Line">Notifications</DropdownMenuItem>
|
|
47
|
+
</DropdownMenuContent>
|
|
48
|
+
</DropdownMenu>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {Avatar} from 'components/avatar';
|
|
2
|
+
import {Button} from 'components/button';
|
|
3
|
+
import {Icon} from 'components/icon';
|
|
4
|
+
import {
|
|
5
|
+
Select,
|
|
6
|
+
SelectContent,
|
|
7
|
+
SelectItem,
|
|
8
|
+
SelectSeparator,
|
|
9
|
+
SelectTrigger,
|
|
10
|
+
SelectValue,
|
|
11
|
+
} from 'components/select';
|
|
12
|
+
|
|
13
|
+
export function OrganizationSelector() {
|
|
14
|
+
return (
|
|
15
|
+
<Select defaultValue="stripe">
|
|
16
|
+
<SelectTrigger className="w-200 h-40 shadow-none bg-background-neutral-base hover:bg-background-neutral-hover rounded-none gap-8 pl-12 border-l min-[321px]:border-r border-border-neutral-strong">
|
|
17
|
+
<div className="flex items-center gap-8 flex-1 min-w-0">
|
|
18
|
+
<SelectValue placeholder="Select organization" />
|
|
19
|
+
</div>
|
|
20
|
+
</SelectTrigger>
|
|
21
|
+
<SelectContent>
|
|
22
|
+
<SelectItem value="stripe">
|
|
23
|
+
<div className="flex items-center gap-8">
|
|
24
|
+
<Avatar size="3xs" content="logo" logoName="stripe" radius="rounded" />
|
|
25
|
+
<span>Stripe</span>
|
|
26
|
+
</div>
|
|
27
|
+
</SelectItem>
|
|
28
|
+
<SelectItem value="shipfox">
|
|
29
|
+
<div className="flex items-center gap-8">
|
|
30
|
+
<Avatar size="3xs" content="logo" logoName="shipfox" radius="rounded" />
|
|
31
|
+
<span>Shipfox</span>
|
|
32
|
+
</div>
|
|
33
|
+
</SelectItem>
|
|
34
|
+
<SelectItem value="github">
|
|
35
|
+
<div className="flex items-center gap-8">
|
|
36
|
+
<Avatar size="3xs" content="logo" logoName="github" radius="rounded" />
|
|
37
|
+
<span>GitHub</span>
|
|
38
|
+
</div>
|
|
39
|
+
</SelectItem>
|
|
40
|
+
<SelectSeparator />
|
|
41
|
+
<Button
|
|
42
|
+
variant="transparent"
|
|
43
|
+
className="w-full justify-start text-foreground-neutral-subtle"
|
|
44
|
+
>
|
|
45
|
+
<Icon name="addLine" className="size-16 shrink-0" />
|
|
46
|
+
<span>New organization</span>
|
|
47
|
+
</Button>
|
|
48
|
+
</SelectContent>
|
|
49
|
+
</Select>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {Tabs, TabsList, TabsTrigger} from 'components/tabs';
|
|
2
|
+
|
|
3
|
+
export function TopMenu({
|
|
4
|
+
activeTab,
|
|
5
|
+
onTabChange,
|
|
6
|
+
}: {
|
|
7
|
+
activeTab: string;
|
|
8
|
+
onTabChange: (tab: string) => void;
|
|
9
|
+
}) {
|
|
10
|
+
return (
|
|
11
|
+
<div className="flex items-center justify-between w-full">
|
|
12
|
+
<div className="flex items-center flex-1 min-w-0 pl-12 md:pl-20 pr-8">
|
|
13
|
+
<Tabs value={activeTab} onValueChange={onTabChange}>
|
|
14
|
+
<TabsList className="h-48 gap-8 md:gap-12">
|
|
15
|
+
<TabsTrigger value="analytics" className="text-sm font-medium">
|
|
16
|
+
Analytics
|
|
17
|
+
</TabsTrigger>
|
|
18
|
+
<TabsTrigger value="jobs" className="text-sm font-medium">
|
|
19
|
+
Jobs
|
|
20
|
+
</TabsTrigger>
|
|
21
|
+
</TabsList>
|
|
22
|
+
</Tabs>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {Button} from 'components/button';
|
|
2
|
+
import {Icon, type IconName} from 'components/icon';
|
|
3
|
+
import {cn} from 'utils/cn';
|
|
4
|
+
|
|
5
|
+
export function TopbarButton({
|
|
6
|
+
className,
|
|
7
|
+
icon,
|
|
8
|
+
label,
|
|
9
|
+
}: {
|
|
10
|
+
className?: string;
|
|
11
|
+
icon: IconName;
|
|
12
|
+
label?: string;
|
|
13
|
+
}) {
|
|
14
|
+
return (
|
|
15
|
+
<Button
|
|
16
|
+
type="button"
|
|
17
|
+
variant="transparent"
|
|
18
|
+
className={cn(
|
|
19
|
+
'flex items-center justify-center overflow-hidden shrink-0 w-40 h-40 bg-background-subtle-base hover:bg-background-neutral-hover transition-colors rounded-none border-l border-border-neutral-strong',
|
|
20
|
+
className,
|
|
21
|
+
)}
|
|
22
|
+
aria-label={label ?? undefined}
|
|
23
|
+
>
|
|
24
|
+
<Icon name={icon} className="size-18 text-foreground-neutral-subtle" />
|
|
25
|
+
</Button>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {cn} from 'utils/cn';
|
|
2
|
+
import {CompleteSetupButton} from './complete-setup-button';
|
|
3
|
+
import {MobileMenu} from './mobile-menu';
|
|
4
|
+
import {OrganizationSelector} from './organization-selector';
|
|
5
|
+
import {TopbarButton} from './topbar-button';
|
|
6
|
+
import {UserProfile} from './user-profile';
|
|
7
|
+
|
|
8
|
+
export function Topbar({hideLogo = false}: {hideLogo?: boolean}) {
|
|
9
|
+
return (
|
|
10
|
+
<div className="flex flex-col items-start w-full bg-background-subtle-base">
|
|
11
|
+
<div className="flex items-center justify-between w-full shrink-0 border-b border-border-neutral-strong">
|
|
12
|
+
<div className="flex items-center flex-1 min-w-0">
|
|
13
|
+
<div className={cn('shrink-0', hideLogo ? 'opacity-0' : 'opacity-100')}>
|
|
14
|
+
<TopbarButton icon="shipfox" label="Shipfox" className="border-none" />
|
|
15
|
+
</div>
|
|
16
|
+
<OrganizationSelector />
|
|
17
|
+
<div className="hidden md:block flex-1 h-40 bg-background-subtle-base" />
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<CompleteSetupButton className="hidden md:flex" />
|
|
21
|
+
|
|
22
|
+
<div className="hidden md:block">
|
|
23
|
+
<TopbarButton icon="searchLine" label="Search" />
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div className="hidden md:block">
|
|
27
|
+
<TopbarButton icon="questionLine" label="Help" />
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div className="hidden md:block">
|
|
31
|
+
<TopbarButton icon="notification3Line" label="Notifications" />
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<MobileMenu />
|
|
35
|
+
|
|
36
|
+
<UserProfile />
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|