-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #64 from argos-ci/pricing-page
feat: add pricing page
- Loading branch information
Showing
10 changed files
with
765 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { clsx } from "clsx"; | ||
import { HTMLProps } from "react"; | ||
|
||
export const Card = ({ className, ...props }: HTMLProps<HTMLDivElement>) => { | ||
return ( | ||
<div | ||
className={clsx( | ||
className, | ||
"w-full rounded-xl border border-border bg-slate-900/50" | ||
)} | ||
{...props} | ||
/> | ||
); | ||
}; | ||
|
||
export const CardBody = ({ | ||
className, | ||
...props | ||
}: HTMLProps<HTMLDivElement>) => { | ||
return <div className={clsx(className, "font-ms p-4")} {...props} />; | ||
}; | ||
|
||
export const CardFooter = ({ | ||
className, | ||
...props | ||
}: HTMLProps<HTMLDivElement>) => { | ||
return ( | ||
<div | ||
className={clsx(className, "bg-slate-900/70 p-4 text-sm")} | ||
{...props} | ||
/> | ||
); | ||
}; | ||
|
||
export const CardTitle = ({ | ||
className, | ||
...props | ||
}: HTMLProps<HTMLDivElement>) => { | ||
return ( | ||
<h2 className={clsx(className, "mb-2 text-xl font-semibold")} {...props} /> | ||
); | ||
}; | ||
|
||
export const CardParagraph = ({ | ||
className, | ||
...props | ||
}: HTMLProps<HTMLDivElement>) => { | ||
return <p className={clsx(className, "my-2 last-of-type:mb-0")} {...props} />; | ||
}; | ||
|
||
export const CardSeparator = ({ | ||
className, | ||
...props | ||
}: HTMLProps<HTMLDivElement>) => { | ||
return ( | ||
<div | ||
role="separator" | ||
aria-orientation="horizontal" | ||
className={clsx(className, "border-t border-t-menu-border")} | ||
{...props} | ||
/> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import { | ||
Tooltip as AriakitTooltip, | ||
TooltipAnchor as AriakitTooltipAnchor, | ||
TooltipStateProps, | ||
useTooltipState as useAriakitTooltipState, | ||
} from "ariakit/tooltip"; | ||
import type { | ||
TooltipAnchorProps as AriakitTooltipAnchorProps, | ||
TooltipProps as AriakitTooltipProps, | ||
} from "ariakit/tooltip"; | ||
import { clsx } from "clsx"; | ||
import { | ||
Children, | ||
cloneElement, | ||
forwardRef, | ||
useLayoutEffect, | ||
useRef, | ||
useState, | ||
} from "react"; | ||
|
||
import { useEventCallback } from "./useEventCallback"; | ||
|
||
const useTooltipState = (props?: TooltipStateProps) => | ||
useAriakitTooltipState({ timeout: 800, ...props }); | ||
|
||
type TooltipAnchorProps = AriakitTooltipAnchorProps; | ||
const TooltipAnchor = AriakitTooltipAnchor; | ||
|
||
export type TooltipVariant = "default" | "info"; | ||
|
||
type TooltipProps = { | ||
variant?: TooltipVariant | undefined; | ||
} & AriakitTooltipProps<"div">; | ||
|
||
const variantClassNames: Record<TooltipVariant, string> = { | ||
default: "text-xs py-1 px-2 text-danger-500", | ||
info: "text-sm p-2 [&_strong]:font-medium", | ||
}; | ||
|
||
const Tooltip = forwardRef<HTMLDivElement, TooltipProps>( | ||
({ variant = "default", ...props }, ref) => { | ||
const variantClassName = variantClassNames[variant]; | ||
if (!variantClassName) { | ||
throw new Error(`Invalid variant: ${variant}`); | ||
} | ||
return ( | ||
<AriakitTooltip | ||
ref={ref} | ||
className={clsx( | ||
variantClassName, | ||
"z-50 rounded border border-tooltip-border bg-tooltip-bg text-tooltip-on" | ||
)} | ||
{...props} | ||
/> | ||
); | ||
} | ||
); | ||
|
||
export type MagicTooltipProps = { | ||
tooltip: React.ReactNode; | ||
variant?: TooltipVariant; | ||
children: React.ReactElement; | ||
timeout?: number; | ||
} & Omit<TooltipAnchorProps, "children" | "state">; | ||
|
||
type ActiveMagicTooltipProps = MagicTooltipProps & { | ||
focusRef: React.MutableRefObject<boolean>; | ||
hoverRef: React.MutableRefObject<boolean>; | ||
timeout?: number; | ||
}; | ||
|
||
const ActiveMagicTooltip = forwardRef<HTMLDivElement, ActiveMagicTooltipProps>( | ||
(props, ref) => { | ||
const { | ||
tooltip, | ||
children, | ||
hoverRef, | ||
focusRef, | ||
variant, | ||
timeout, | ||
...restProps | ||
} = props; | ||
const state = useTooltipState({ timeout }); | ||
const { render, show } = state; | ||
useLayoutEffect(() => { | ||
if (hoverRef.current || focusRef.current) { | ||
render(); | ||
show(); | ||
} | ||
}, [render, show, hoverRef, focusRef]); | ||
|
||
return ( | ||
<> | ||
<TooltipAnchor ref={ref} state={state} {...restProps}> | ||
{(referenceProps) => cloneElement(children, referenceProps)} | ||
</TooltipAnchor> | ||
<Tooltip state={state} variant={variant}> | ||
{tooltip} | ||
</Tooltip> | ||
</> | ||
); | ||
} | ||
); | ||
|
||
export const MagicTooltip = forwardRef<HTMLDivElement, MagicTooltipProps>( | ||
({ children, ...props }, ref) => { | ||
const [active, setActive] = useState(false); | ||
const hoverRef = useRef(false); | ||
const handleMouseEnter = useEventCallback( | ||
(event: React.MouseEvent<HTMLDivElement, MouseEvent>) => { | ||
props.onMouseEnter?.(event); | ||
hoverRef.current = true; | ||
setActive(true); | ||
} | ||
); | ||
const handleMouseLeave = useEventCallback( | ||
(event: React.MouseEvent<HTMLDivElement, MouseEvent>) => { | ||
props.onMouseLeave?.(event); | ||
hoverRef.current = false; | ||
} | ||
); | ||
const focusRef = useRef(false); | ||
const handleFocus = useEventCallback( | ||
(event: React.FocusEvent<HTMLDivElement>) => { | ||
props.onFocus?.(event); | ||
focusRef.current = true; | ||
setActive(true); | ||
} | ||
); | ||
const handleBlur = useEventCallback( | ||
(event: React.FocusEvent<HTMLDivElement>) => { | ||
props.onBlur?.(event); | ||
focusRef.current = false; | ||
} | ||
); | ||
|
||
const child = Children.only(children); | ||
if (!props.tooltip) { | ||
return cloneElement(child, props); | ||
} | ||
if (!active) { | ||
const childProps = { | ||
...props, | ||
ref, | ||
onMouseEnter: handleMouseEnter, | ||
onMouseLeave: handleMouseLeave, | ||
onFocus: handleFocus, | ||
onBlur: handleBlur, | ||
} as Record<string, any>; | ||
if (typeof props.tooltip === "string" && !child.props["aria-label"]) { | ||
childProps["aria-label"] = props["aria-label"] ?? props.tooltip; | ||
} | ||
return cloneElement(child, childProps); | ||
} | ||
|
||
return ( | ||
<ActiveMagicTooltip {...props} hoverRef={hoverRef} focusRef={focusRef}> | ||
{child} | ||
</ActiveMagicTooltip> | ||
); | ||
} | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { useLayoutEffect, useMemo, useRef } from "react"; | ||
|
||
type Fn<ARGS extends any[], R> = (...args: ARGS) => R; | ||
|
||
/** | ||
* # React hook `useEventCallback` | ||
* Aimed to be easier to use than `useCallback` and solve problems raised in [this ticket](https://github.com/facebook/react/issues/14099). | ||
* | ||
* `useEventCallback` doesn't need any dependencies list. | ||
* The returned function should not be used during rendering. | ||
* | ||
* ### Example | ||
* | ||
* ```jsx | ||
* import useEventCallback from 'use-event-callback'; | ||
* const Input = () => { | ||
* const [value, setValue] = useState(''); | ||
* const onChange = useEventCallback((event) => { | ||
* setValue(event.target.value); | ||
* }); | ||
* return <input value={value} onChange={onChange} />; | ||
* } | ||
*/ | ||
export const useEventCallback = <A extends any[], R>( | ||
fn: Fn<A, R> | ||
): Fn<A, R> => { | ||
const ref = useRef<Fn<A, R>>(fn); | ||
useLayoutEffect(() => { | ||
ref.current = fn; | ||
}); | ||
return useMemo( | ||
() => | ||
(...args: A): R => { | ||
const { current } = ref; | ||
return current(...args); | ||
}, | ||
[] | ||
); | ||
}; | ||
|
||
export default useEventCallback; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
ca176cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checks for Deployment have failed