Move to infisical. Create local dev environment. Add ci gates. Modernize repo
Build and Push Next App / quality (push) Successful in 1m8s
Build and Push Next App / build-next (push) Successful in 2m59s

This commit is contained in:
Gabriel Brown
2026-06-21 14:04:02 -05:00
parent 86e2fdc82e
commit a12bf6071b
79 changed files with 1612 additions and 42168 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+7
View File
@@ -12,6 +12,9 @@
"format": "prettier --check . --ignore-path ../../.gitignore",
"lint": "eslint --flag unstable_native_nodejs_ts_config",
"typecheck": "tsc --noEmit --emitDeclarationOnly false",
"test:unit": "vitest run --project unit --passWithNoTests",
"test:integration": "vitest run --project integration --passWithNoTests",
"test:component": "NODE_ENV=test vitest run --project component",
"ui-add": "bunx --bun shadcn@latest add && prettier src --write --list-different"
},
"dependencies": {
@@ -53,11 +56,15 @@
"@gib/eslint-config": "workspace:*",
"@gib/prettier-config": "workspace:*",
"@gib/tsconfig": "workspace:*",
"@gib/vitest-config": "workspace:*",
"@testing-library/react": "catalog:test",
"@types/react": "catalog:react19",
"eslint": "catalog:",
"jsdom": "catalog:test",
"prettier": "catalog:",
"react": "catalog:react19",
"typescript": "catalog:",
"vitest": "catalog:test",
"zod": "catalog:"
},
"peerDependencies": {
+1 -1
View File
@@ -21,7 +21,7 @@ const BasedProgress = ({
value = 0,
...props
}: BasedProgressProps) => {
const [progress, setProgress] = React.useState<number>(value);
const [progress, setProgress] = React.useState<number>(value ?? 0);
React.useEffect(() => {
const id = window.setInterval(() => {
+44 -19
View File
@@ -105,6 +105,15 @@ ${colorConfig
const ChartTooltip = RechartsPrimitive.Tooltip;
type ChartPayloadItem = {
name?: string | number;
value?: number | string;
dataKey?: string | number;
type?: string;
color?: string;
payload?: Record<string, unknown> & { fill?: string };
};
const ChartTooltipContent = ({
active,
payload,
@@ -119,14 +128,29 @@ const ChartTooltipContent = ({
color,
nameKey,
labelKey,
}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
React.ComponentProps<'div'> & {
hideLabel?: boolean;
hideIndicator?: boolean;
indicator?: 'line' | 'dot' | 'dashed';
nameKey?: string;
labelKey?: string;
}) => {
}: React.ComponentProps<'div'> & {
active?: boolean;
payload?: ChartPayloadItem[];
label?: React.ReactNode;
labelFormatter?: (
value: React.ReactNode,
payload: ChartPayloadItem[],
) => React.ReactNode;
formatter?: (
value: number | string,
name: string | number,
item: ChartPayloadItem,
index: number,
itemPayload: ChartPayloadItem['payload'],
) => React.ReactNode;
color?: string;
labelClassName?: string;
hideLabel?: boolean;
hideIndicator?: boolean;
indicator?: 'line' | 'dot' | 'dashed';
nameKey?: string;
labelKey?: string;
}) => {
const { config } = useChart();
const tooltipLabel = React.useMemo(() => {
@@ -139,7 +163,7 @@ const ChartTooltipContent = ({
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const value =
!labelKey && typeof label === 'string'
? config[label]?.label ?? label
? (config[label]?.label ?? label)
: itemConfig?.label;
if (labelFormatter) {
@@ -185,17 +209,17 @@ const ChartTooltipContent = ({
.map((item, index) => {
const key = `${nameKey ?? item.name ?? item.dataKey ?? 'value'}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const indicatorColor = color ?? item.payload.fill ?? item.color;
const indicatorColor = color ?? item.payload?.fill ?? item.color;
return (
<div
key={item.dataKey}
key={item.dataKey ?? index}
className={cn(
'[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5',
indicator === 'dot' && 'items-center',
)}
>
{formatter && item?.value !== undefined && item.name ? (
{formatter && item.value !== undefined && item.name ? (
formatter(item.value, item.name, item, index, item.payload)
) : (
<>
@@ -259,11 +283,12 @@ const ChartLegendContent = ({
payload,
verticalAlign = 'bottom',
nameKey,
}: React.ComponentProps<'div'> &
Pick<RechartsPrimitive.LegendProps, 'payload' | 'verticalAlign'> & {
hideIcon?: boolean;
nameKey?: string;
}) => {
}: React.ComponentProps<'div'> & {
payload?: ChartPayloadItem[];
verticalAlign?: 'top' | 'bottom';
hideIcon?: boolean;
nameKey?: string;
}) => {
const { config } = useChart();
if (!payload?.length) {
@@ -280,13 +305,13 @@ const ChartLegendContent = ({
>
{payload
.filter((item) => item.type !== 'none')
.map((item) => {
.map((item, index) => {
const key = `${nameKey ?? item.dataKey ?? 'value'}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
return (
<div
key={item.value}
key={item.value ?? index}
className={cn(
'[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3',
)}
+10 -7
View File
@@ -68,13 +68,16 @@ const ComboboxInput = ({
/>
<InputGroupAddon align='inline-end'>
{showTrigger && (
<InputGroupButton
size='icon-xs'
variant='ghost'
render={<ComboboxTrigger />}
data-slot='input-group-button'
className='group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent'
disabled={disabled}
<ComboboxTrigger
render={
<InputGroupButton
size='icon-xs'
variant='ghost'
data-slot='input-group-button'
className='group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent'
disabled={disabled}
/>
}
/>
)}
{showClear && <ComboboxClear disabled={disabled} />}
+1
View File
@@ -0,0 +1 @@
declare module '*.css';
+19 -15
View File
@@ -294,19 +294,17 @@ export const ImageCropApply = ({
if (asChild) {
return (
<Slot.Root onClick={handleClick} {...(props as any)}>
<Slot.Root
onClick={handleClick}
{...(props as ComponentProps<typeof Slot.Root>)}
>
{children}
</Slot.Root>
);
}
return (
<Button
onClick={handleClick}
size='icon'
variant='ghost'
{...(props as any)}
>
<Button onClick={handleClick} size='icon' variant='ghost' {...props}>
{children ?? <CropIcon className='size-4' />}
</Button>
);
@@ -331,19 +329,17 @@ export const ImageCropReset = ({
if (asChild) {
return (
<Slot.Root onClick={handleClick} {...(props as any)}>
<Slot.Root
onClick={handleClick}
{...(props as ComponentProps<typeof Slot.Root>)}
>
{children}
</Slot.Root>
);
}
return (
<Button
onClick={handleClick}
size='icon'
variant='ghost'
{...(props as any)}
>
<Button onClick={handleClick} size='icon' variant='ghost' {...props}>
{children ?? <RotateCcwIcon className='size-4' />}
</Button>
);
@@ -373,7 +369,15 @@ export const Cropper = ({
onChange={onChange}
onComplete={onComplete}
onCrop={onCrop}
{...(props as any)}
{...(props as Omit<
ImageCropProps,
| 'file'
| 'maxImageSize'
| 'onChange'
| 'onComplete'
| 'onCrop'
| 'children'
>)}
>
<ImageCropContent className={className} style={style} />
</ImageCrop>
@@ -0,0 +1,13 @@
import { render, screen } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import { Button } from '../../src/button';
describe('Button', () => {
it('renders its children', () => {
render(<Button>Click me</Button>);
expect(
screen.getByRole('button', { name: 'Click me' }),
).toBeInTheDocument();
});
});
+1
View File
@@ -0,0 +1 @@
import '@testing-library/jest-dom/vitest';
+1 -1
View File
@@ -5,6 +5,6 @@
"jsx": "preserve",
"rootDir": "."
},
"include": ["src"],
"include": ["src", "tests", "vitest.config.ts"],
"exclude": ["node_modules"]
}
+13
View File
@@ -0,0 +1,13 @@
import { defineConfig } from 'vitest/config';
import { jsdomProject, nodeProject } from '@gib/vitest-config';
export default defineConfig({
test: {
projects: [
nodeProject('unit', ['tests/unit/**/*.test.{ts,tsx}']),
nodeProject('integration', ['tests/integration/**/*.test.{ts,tsx}']),
jsdomProject('component', ['tests/component/**/*.test.{ts,tsx}']),
],
},
});