A design system in a box. hip-ui.tngl.io/docs/introduction
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

1 match page done

+1360 -56
+11 -3
apps/docs/src/components/card/index.tsx
··· 13 13 flexDirection: "column", 14 14 fontFamily: fontFamily["sans"], 15 15 gap: spacing["6"], 16 - width: "fit-content", 17 16 }, 18 17 cardHeader: { 19 18 paddingBottom: { ":last-child": spacing["4"] }, ··· 22 21 paddingTop: spacing["5"], 23 22 }, 24 23 cardTitle: { 25 - fontSize: fontSize["lg"], 24 + fontSize: fontSize["xl"], 26 25 fontWeight: fontWeight["bold"], 27 26 }, 28 27 cardDescription: { ··· 31 30 margin: 0, 32 31 }, 33 32 cardBody: { 33 + display: "flex", 34 + flexDirection: "column", 35 + gap: spacing["6"], 34 36 paddingBottom: { ":last-child": spacing["4"] }, 35 37 paddingLeft: spacing["4"], 36 38 paddingRight: spacing["4"], ··· 55 57 return ( 56 58 <div 57 59 {...props} 58 - {...stylex.props(styles.card, gray.bgSubtle, gray.border, style)} 60 + {...stylex.props( 61 + styles.card, 62 + gray.bgSubtle, 63 + gray.border, 64 + gray.text, 65 + style, 66 + )} 59 67 /> 60 68 ); 61 69 };
+73
apps/docs/src/components/switch/index.tsx
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + import { 3 + SwitchProps as AriaSwitchProps, 4 + Switch as AriaSwitch, 5 + } from "react-aria-components"; 6 + 7 + import { plum, slate } from "../theme/colors.stylex"; 8 + import { radius } from "../theme/radius.stylex"; 9 + import { shadow } from "../theme/shadow.stylex"; 10 + import { spacing } from "../theme/spacing.stylex"; 11 + import { typeramp } from "../theme/typography.stylex"; 12 + 13 + const styles = stylex.create({ 14 + wrapper: { 15 + alignItems: "center", 16 + display: "flex", 17 + gap: spacing["2"], 18 + }, 19 + indicator: { 20 + backgroundColor: { 21 + default: slate.component3, 22 + ":is([data-selected=true] *)": plum.solid1, 23 + }, 24 + borderRadius: radius.full, 25 + height: spacing["6"], 26 + opacity: { 27 + default: 1, 28 + ":is([data-disabled=true] *)": 0.5, 29 + }, 30 + position: "relative", 31 + transitionDuration: "100ms", 32 + transitionProperty: "background-color", 33 + transitionTimingFunction: "ease-in-out", 34 + width: spacing["10"], 35 + }, 36 + thumb: { 37 + backgroundColor: slate.bg2, 38 + borderRadius: radius.full, 39 + boxShadow: shadow.lg, 40 + content: "''", 41 + height: spacing["4"], 42 + left: 0, 43 + marginLeft: spacing["1"], 44 + marginRight: spacing["1"], 45 + position: "absolute", 46 + top: "50%", 47 + transform: { 48 + default: "translateY(-50%)", 49 + ":is([data-selected=true] *)": "translate(100%, -50%)", 50 + }, 51 + transitionDuration: "100ms", 52 + transitionProperty: "transform", 53 + transitionTimingFunction: "ease-in-out", 54 + width: spacing["4"], 55 + }, 56 + }); 57 + 58 + export interface SwitchProps 59 + extends Omit<AriaSwitchProps, "children" | "style" | "className"> { 60 + style?: stylex.StyleXStyles | stylex.StyleXStyles[]; 61 + children: React.ReactNode; 62 + } 63 + 64 + export function Switch({ children, style, ...props }: SwitchProps) { 65 + return ( 66 + <AriaSwitch {...props} {...stylex.props(styles.wrapper, style)}> 67 + <div {...stylex.props(styles.indicator)}> 68 + <div {...stylex.props(styles.thumb)} /> 69 + </div> 70 + <div {...stylex.props(typeramp.label)}>{children}</div> 71 + </AriaSwitch> 72 + ); 73 + }
+14 -14
apps/docs/src/components/theme/semantic-color.stylex.tsx
··· 53 53 backgroundColor: { 54 54 default: slate.component1, 55 55 ":hover:not(:has(* button:hover)):not(:disabled)": slate.component2, 56 - ":active:not(:disabled)": slate.component3, 56 + ":is(:active,[data-pressed=true]):not(:disabled)": slate.component3, 57 57 ":disabled": slate.component1, 58 58 }, 59 59 transitionDuration: "100ms", ··· 64 64 backgroundColor: { 65 65 default: slate.component2, 66 66 ":hover:not(:has(* button:hover)):not(:disabled)": slate.component3, 67 - ":active:not(:disabled)": slate.component3, 67 + ":is(:active,[data-pressed=true]):not(:disabled)": slate.component3, 68 68 ":disabled": slate.component1, 69 69 }, 70 70 transitionDuration: "100ms", ··· 112 112 backgroundColor: { 113 113 default: "transparent", 114 114 ":hover:not(:has(* button:hover)):not(:disabled)": plum.component2, 115 - ":active:not(:disabled)": plum.component3, 115 + ":is(:active,[data-pressed=true]):not(:disabled)": plum.component3, 116 116 ":disabled": plum.component1, 117 117 }, 118 118 transitionDuration: "100ms", ··· 123 123 backgroundColor: { 124 124 default: plum.component1, 125 125 ":hover:not(:has(* button:hover)):not(:disabled)": plum.component2, 126 - ":active": plum.component3, 126 + ":is(:active,[data-pressed=true])": plum.component3, 127 127 ":disabled": plum.component1, 128 128 }, 129 129 transitionDuration: "100ms", ··· 134 134 backgroundColor: { 135 135 default: plum.component2, 136 136 ":hover:not(:has(* button:hover)):not(:disabled)": plum.component3, 137 - ":active:not(:disabled)": plum.component3, 137 + ":is(:active,[data-pressed=true]):not(:disabled)": plum.component3, 138 138 ":disabled": plum.component1, 139 139 }, 140 140 transitionDuration: "100ms", ··· 181 181 backgroundColor: { 182 182 default: "transparent", 183 183 ":hover:not(:has(* button:hover)):not(:disabled)": red.component2, 184 - ":active:not(:disabled)": red.component3, 184 + ":is(:active,[data-pressed=true]):not(:disabled)": red.component3, 185 185 ":disabled": red.component1, 186 186 }, 187 187 transitionDuration: "100ms", ··· 192 192 backgroundColor: { 193 193 default: red.component1, 194 194 ":hover:not(:has(* button:hover)):not(:disabled)": red.component2, 195 - ":active:not(:disabled)": red.component3, 195 + ":is(:active,[data-pressed=true]):not(:disabled)": red.component3, 196 196 ":disabled": red.component1, 197 197 }, 198 198 transitionDuration: "100ms", ··· 203 203 backgroundColor: { 204 204 default: red.component2, 205 205 ":hover:not(:has(* button:hover)):not(:disabled)": red.component3, 206 - ":active:not(:disabled)": red.component3, 206 + ":is(:active,[data-pressed=true]):not(:disabled)": red.component3, 207 207 ":disabled": red.component1, 208 208 }, 209 209 transitionDuration: "100ms", ··· 255 255 backgroundColor: { 256 256 default: "transparent", 257 257 ":hover:not(:has(* button:hover)):not(:disabled)": yellow.component2, 258 - ":active:not(:disabled)": yellow.component3, 258 + ":is(:active,[data-pressed=true]):not(:disabled)": yellow.component3, 259 259 ":disabled": yellow.component1, 260 260 }, 261 261 transitionDuration: "100ms", ··· 266 266 backgroundColor: { 267 267 default: yellow.component1, 268 268 ":hover:not(:has(* button:hover)):not(:disabled)": yellow.component2, 269 - ":active:not(:disabled)": yellow.component3, 269 + ":is(:active,[data-pressed=true]):not(:disabled)": yellow.component3, 270 270 ":disabled": yellow.component1, 271 271 }, 272 272 transitionDuration: "100ms", ··· 277 277 backgroundColor: { 278 278 default: yellow.component2, 279 279 ":hover:not(:has(* button:hover)):not(:disabled)": yellow.component3, 280 - ":active:not(:disabled)": yellow.component3, 280 + ":is(:active,[data-pressed=true]):not(:disabled)": yellow.component3, 281 281 ":disabled": yellow.component1, 282 282 }, 283 283 transitionDuration: "100ms", ··· 334 334 backgroundColor: { 335 335 default: "transparent", 336 336 ":hover:not(:has(* button:hover)):not(:disabled)": green.component2, 337 - ":active:not(:disabled)": green.component3, 337 + ":is(:active,[data-pressed=true]):not(:disabled)": green.component3, 338 338 ":disabled": green.component1, 339 339 }, 340 340 transitionDuration: "100ms", ··· 345 345 backgroundColor: { 346 346 default: green.component1, 347 347 ":hover:not(:has(* button:hover)):not(:disabled)": green.component2, 348 - ":active:not(:disabled)": green.component3, 348 + ":is(:active,[data-pressed=true]):not(:disabled)": green.component3, 349 349 ":disabled": green.component1, 350 350 }, 351 351 transitionDuration: "100ms", ··· 356 356 backgroundColor: { 357 357 default: green.component2, 358 358 ":hover:not(:has(* button:hover)):not(:disabled)": green.component3, 359 - ":active:not(:disabled)": green.component3, 359 + ":is(:active,[data-pressed=true]):not(:disabled)": green.component3, 360 360 ":disabled": green.component1, 361 361 }, 362 362 transitionDuration: "100ms",
+3 -1
apps/docs/src/components/theme/spacing.stylex.tsx
··· 1 1 import * as stylex from "@stylexjs/stylex"; 2 2 3 + import { ThemeKeys } from "./types"; 4 + 3 5 export const spacing = stylex.defineVars({ 4 6 px: "1px", 5 7 "0": "0px", ··· 39 41 }); 40 42 41 43 // eslint-disable-next-line @stylexjs/enforce-extension 42 - export type Spacing = keyof typeof spacing; 44 + export type Spacing = ThemeKeys<typeof spacing>;
+4
apps/docs/src/components/theme/types.ts
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + 3 + export type ThemeKeys<T> = 4 + T extends stylex.VarGroup<Readonly<infer Tokens>> ? keyof Tokens : never;
+3 -1
apps/docs/src/components/theme/typography.stylex.tsx
··· 4 4 import { spacing } from "./spacing.stylex"; 5 5 6 6 export const fontFamily = stylex.defineVars({ 7 - sans: "Inter, sans-serif", 7 + sans: "'Inter', sans-serif", 8 8 serif: "Georgia, serif", 9 9 mono: "Monaco, monospace", 10 10 }); ··· 131 131 fontWeight: fontWeight["semibold"], 132 132 letterSpacing: tracking["tight"], 133 133 lineHeight: { default: lineHeight["lg"] }, 134 + margin: 0, 135 + scrollMarginBlockStart: spacing["20"], 134 136 }, 135 137 body: { 136 138 // eslint-disable-next-line @stylexjs/valid-styles
+6 -4
apps/docs/src/components/theme/useButtonStyles.ts
··· 90 90 }, 91 91 paddingRight: spacing["4"], 92 92 }, 93 - outline: { 94 - borderWidth: 1, 95 - }, 96 93 secondary: { 97 94 borderColor: { 98 95 default: slate.component1, ··· 168 165 gray.borderInteractive, 169 166 gray.bgGhost, 170 167 gray.text, 171 - styles.outline, 172 168 styles.shadow, 173 169 ], 174 170 variant === "critical" && [ 175 171 critical.bgSolidAction, 176 172 critical.borderInteractive, 177 173 critical.textContrast, 174 + styles.shadow, 175 + ], 176 + variant === "critical-outline" && [ 177 + critical.borderInteractive, 178 + critical.bgGhost, 179 + critical.text, 178 180 styles.shadow, 179 181 ], 180 182 size === "sm" && styles.small,
+7
apps/docs/src/components/toggle-button/index.tsx
··· 56 56 ":active": slate.border3, 57 57 }, 58 58 }, 59 + "critical-outlineSelected": { 60 + backgroundColor: { 61 + default: slate.border1, 62 + ":hover": slate.border2, 63 + ":active": slate.border3, 64 + }, 65 + }, 59 66 sm: { 60 67 paddingLeft: { 61 68 ":has(> * + *, > *:not(svg):only-child)": spacing["2"],
+2 -1
apps/docs/src/components/types.ts
··· 4 4 | "secondary" 5 5 | "tertiary" 6 6 | "outline" 7 - | "critical"; 7 + | "critical" 8 + | "critical-outline";
+36 -8
apps/docs/src/components/typography/index.tsx
··· 97 97 return <h4 {...stylex.props(typeramp.heading4, style)} {...props} />; 98 98 }; 99 99 100 + export interface Heading5Props 101 + extends Omit<React.ComponentProps<"h5">, "style" | "className"> { 102 + style?: stylex.StyleXStyles | stylex.StyleXStyles[]; 103 + } 104 + 105 + export const Heading5 = ({ style, ...props }: Heading5Props) => { 106 + // eslint-disable-next-line jsx-a11y/heading-has-content 107 + return <h5 {...stylex.props(typeramp.heading5, style)} {...props} />; 108 + }; 109 + 100 110 export interface BodyProps 101 111 extends Omit<React.ComponentProps<"p">, "style" | "className"> { 102 112 style?: stylex.StyleXStyles | stylex.StyleXStyles[]; ··· 129 139 variant = "default", 130 140 ...props 131 141 }: SmallBodyProps) => { 142 + const contextValue = useMemo( 143 + () => ({ 144 + style: [variant === "secondary" && gray.textDim, styles.underline], 145 + }), 146 + [variant], 147 + ); 148 + 132 149 return ( 133 - <p 134 - {...stylex.props( 135 - typeramp.smallBody, 136 - variant === "secondary" && gray.textDim, 137 - style, 138 - )} 139 - {...props} 140 - /> 150 + <LinkContext value={contextValue}> 151 + <p 152 + {...stylex.props( 153 + typeramp.smallBody, 154 + variant === "secondary" && gray.textDim, 155 + style, 156 + )} 157 + {...props} 158 + /> 159 + </LinkContext> 141 160 ); 161 + }; 162 + 163 + interface LabelTextProps 164 + extends Omit<React.ComponentProps<"p">, "style" | "className"> { 165 + style?: stylex.StyleXStyles | stylex.StyleXStyles[]; 166 + } 167 + 168 + export const LabelText = ({ style, ...props }: LabelTextProps) => { 169 + return <p {...stylex.props(typeramp.label, style)} {...props} />; 142 170 }; 143 171 144 172 interface SubLabelProps
+109
apps/docs/src/components/typography/text.tsx
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + 3 + import { red, slate } from "../theme/colors.stylex"; 4 + import { ThemeKeys } from "../theme/types"; 5 + import { 6 + fontFamily, 7 + fontSize, 8 + fontWeight, 9 + lineHeight, 10 + tracking, 11 + } from "../theme/typography.stylex"; 12 + 13 + const styles = stylex.create({ 14 + sans: { fontFamily: fontFamily["sans"] }, 15 + serif: { fontFamily: fontFamily["serif"] }, 16 + mono: { fontFamily: fontFamily["mono"] }, 17 + 18 + thin: { fontWeight: fontWeight["thin"] }, 19 + extralight: { fontWeight: fontWeight["extralight"] }, 20 + light: { fontWeight: fontWeight["light"] }, 21 + normal: { fontWeight: fontWeight["normal"] }, 22 + medium: { fontWeight: fontWeight["medium"] }, 23 + semibold: { fontWeight: fontWeight["semibold"] }, 24 + bold: { fontWeight: fontWeight["bold"] }, 25 + extrabold: { fontWeight: fontWeight["extrabold"] }, 26 + black: { fontWeight: fontWeight["black"] }, 27 + 28 + "font-xs": { fontSize: fontSize["xs"] }, 29 + "font-sm": { fontSize: fontSize["sm"] }, 30 + "font-base": { fontSize: fontSize["base"] }, 31 + "font-lg": { fontSize: fontSize["lg"] }, 32 + "font-xl": { fontSize: fontSize["xl"] }, 33 + "font-2xl": { fontSize: fontSize["2xl"] }, 34 + "font-3xl": { fontSize: fontSize["3xl"] }, 35 + "font-4xl": { fontSize: fontSize["4xl"] }, 36 + "font-5xl": { fontSize: fontSize["5xl"] }, 37 + "font-6xl": { fontSize: fontSize["6xl"] }, 38 + "font-7xl": { fontSize: fontSize["7xl"] }, 39 + "font-8xl": { fontSize: fontSize["8xl"] }, 40 + "font-9xl": { fontSize: fontSize["9xl"] }, 41 + 42 + "leading-none": { lineHeight: lineHeight["none"] }, 43 + "leading-xs": { lineHeight: lineHeight["xs"] }, 44 + "leading-sm": { lineHeight: lineHeight["sm"] }, 45 + "leading-base": { lineHeight: lineHeight["base"] }, 46 + "leading-lg": { lineHeight: lineHeight["lg"] }, 47 + "leading-xl": { lineHeight: lineHeight["xl"] }, 48 + "leading-2xl": { lineHeight: lineHeight["2xl"] }, 49 + "leading-3xl": { lineHeight: lineHeight["3xl"] }, 50 + "leading-4xl": { lineHeight: lineHeight["4xl"] }, 51 + "leading-5xl": { lineHeight: lineHeight["5xl"] }, 52 + "leading-6xl": { lineHeight: lineHeight["6xl"] }, 53 + "leading-7xl": { lineHeight: lineHeight["7xl"] }, 54 + "leading-8xl": { lineHeight: lineHeight["8xl"] }, 55 + "leading-9xl": { lineHeight: lineHeight["9xl"] }, 56 + 57 + "tracking-tighter": { letterSpacing: tracking["tighter"] }, 58 + "tracking-tight": { letterSpacing: tracking["tight"] }, 59 + "tracking-normal": { letterSpacing: tracking["normal"] }, 60 + "tracking-wide": { letterSpacing: tracking["wide"] }, 61 + "tracking-wider": { letterSpacing: tracking["wider"] }, 62 + "tracking-widest": { letterSpacing: tracking["widest"] }, 63 + 64 + "variant-primary": { color: slate.text2 }, 65 + "variant-secondary": { color: slate.text1 }, 66 + "variant-destructive": { color: red.text2 }, 67 + 68 + strikethrough: { textDecoration: "line-through" }, 69 + }); 70 + 71 + interface TextProps 72 + extends Omit<React.ComponentProps<"span">, "style" | "className"> { 73 + style?: stylex.StyleXStyles | stylex.StyleXStyles[]; 74 + font?: ThemeKeys<typeof fontFamily>; 75 + weight?: ThemeKeys<typeof fontWeight>; 76 + size?: ThemeKeys<typeof fontSize>; 77 + leading?: ThemeKeys<typeof lineHeight>; 78 + tracking?: ThemeKeys<typeof tracking>; 79 + variant?: "primary" | "secondary" | "destructive"; 80 + strikethrough?: boolean; 81 + } 82 + 83 + export const Text = ({ 84 + style, 85 + font = "sans", 86 + weight, 87 + size, 88 + leading, 89 + tracking, 90 + variant, 91 + strikethrough = false, 92 + ...props 93 + }: TextProps) => { 94 + return ( 95 + <span 96 + {...stylex.props( 97 + styles[font], 98 + weight && styles[weight], 99 + size && styles[`font-${size}`], 100 + leading && styles[`leading-${leading}`], 101 + tracking && styles[`tracking-${tracking}`], 102 + variant && styles[`variant-${variant}`], 103 + strikethrough && styles.strikethrough, 104 + style, 105 + )} 106 + {...props} 107 + /> 108 + ); 109 + };
+17 -1
apps/docs/src/routes/__root.tsx
··· 1 1 import { HeadContent, Scripts, createRootRoute } from "@tanstack/react-router"; 2 2 import { TanStackRouterDevtoolsPanel } from "@tanstack/react-router-devtools"; 3 3 import { TanStackDevtools } from "@tanstack/react-devtools"; 4 + import * as stylex from "@stylexjs/stylex"; 5 + import { gray } from "@/components/theme/semantic-color.stylex"; 4 6 5 7 export const Route = createRootRoute({ 6 8 head: () => ({ ··· 16 18 title: "TanStack Start Starter", 17 19 }, 18 20 ], 21 + links: [ 22 + { 23 + rel: "preconnect", 24 + href: "https://fonts.googleapis.com", 25 + }, 26 + { 27 + rel: "preconnect", 28 + href: "https://fonts.gstatic.com", 29 + }, 30 + { 31 + rel: "stylesheet", 32 + href: "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap", 33 + }, 34 + ], 19 35 }), 20 36 21 37 shellComponent: RootDocument, ··· 27 43 <head> 28 44 <HeadContent /> 29 45 </head> 30 - <body> 46 + <body {...stylex.props(gray.bg, gray.text)}> 31 47 {children} 32 48 <TanStackDevtools 33 49 config={{
+802 -5
apps/docs/src/routes/_docs.invoice-app.tsx
··· 4 4 Card, 5 5 CardBody, 6 6 CardDescription, 7 + CardFooter, 7 8 CardHeader, 8 9 CardTitle, 9 10 } from "@/components/card"; ··· 14 15 import { Menu, MenuItem, MenuSeparator } from "@/components/menu"; 15 16 import { Separator } from "@/components/separator"; 16 17 import { TextField } from "@/components/text-field"; 17 - import { SmallBody } from "@/components/typography"; 18 + import { Body, Heading5, SmallBody } from "@/components/typography"; 18 19 import { createFileRoute } from "@tanstack/react-router"; 19 - import { MoreHorizontal } from "lucide-react"; 20 + import { 21 + ArrowDown, 22 + ArrowUp, 23 + CheckCircle, 24 + CheckCircle2, 25 + Copy, 26 + ExternalLink, 27 + MoreHorizontal, 28 + Pin, 29 + Plus, 30 + Share, 31 + X, 32 + } from "lucide-react"; 20 33 import { Fragment } from "react/jsx-runtime"; 21 34 import * as stylex from "@stylexjs/stylex"; 35 + import { Switch } from "@/components/switch"; 36 + import { fontFamily, typeramp } from "../components/theme/typography.stylex"; 37 + import { Text } from "@/components/typography/text"; 38 + import { ToggleButton } from "@/components/toggle-button"; 39 + import { spacing } from "../components/theme/spacing.stylex"; 40 + import { Badge } from "@/components/badge"; 41 + import { Checkbox } from "@/components/checkbox"; 42 + import { green, plum } from "../components/theme/colors.stylex"; 43 + import { gray, primary } from "@/components/theme/semantic-color.stylex"; 44 + import { radius } from "../components/theme/radius.stylex"; 22 45 23 46 const styles = stylex.create({ 47 + relative: { 48 + position: "relative", 49 + }, 50 + textCenter: { 51 + textAlign: "center", 52 + }, 24 53 grow: { 25 54 flexGrow: 1, 55 + flexShrink: 0, 56 + flexBasis: "0%", 57 + minWidth: 0, 58 + }, 59 + skinny: { 60 + flexGrow: 0.75, 61 + flexShrink: 0, 62 + flexBasis: "0%", 63 + }, 64 + pinnedButtons: { 65 + position: "absolute", 66 + top: 0, 67 + right: 0, 68 + marginRight: spacing["4"], 69 + marginTop: spacing["4"], 70 + }, 71 + invoiceCard: { 72 + padding: spacing["6"], 73 + }, 74 + check: { 75 + color: green.solid2, 76 + }, 77 + creditCardWrapper: { 78 + borderRadius: radius["lg"], 79 + padding: spacing["8"], 80 + }, 81 + creditCard: { 82 + fontFamily: fontFamily["mono"], 83 + borderRadius: radius["lg"], 84 + padding: spacing["4"], 85 + height: spacing["40"], 86 + backgroundImage: `linear-gradient(135deg, ${plum.solid2} 0%, ${plum.text1} 100%)`, 87 + }, 88 + copyCardNumber: { 89 + color: "white", 90 + backgroundColor: { 91 + default: "transparent", 92 + ":hover": "rgba(255, 255, 255, 0.3)", 93 + }, 26 94 }, 27 95 }); 28 96 ··· 122 190 ); 123 191 } 124 192 193 + function Pricing() { 194 + return ( 195 + <Card> 196 + <CardHeader> 197 + <CardTitle>Pricing</CardTitle> 198 + <CardDescription> 199 + No credit card required. Every plan includes a 30-day trial of all Pro 200 + features. 201 + </CardDescription> 202 + </CardHeader> 203 + <CardBody> 204 + <Flex gap="8"> 205 + <Flex direction="column" gap="5" style={styles.grow}> 206 + <Flex direction="column" gap="2"> 207 + <Text weight="semibold" size="xl"> 208 + Basic 209 + </Text> 210 + <Text size="sm" variant="secondary"> 211 + 3 team members 212 + </Text> 213 + </Flex> 214 + <Text weight="semibold" size="xl"> 215 + $0<Text variant="secondary">{" / mo"}</Text> 216 + </Text> 217 + <Flex direction="column" gap="2"> 218 + <Flex align="center" gap="2"> 219 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 220 + <Text size="sm">Expense tracking</Text> 221 + </Flex> 222 + <Flex align="center" gap="2"> 223 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 224 + <Text size="sm">Invoicing</Text> 225 + </Flex> 226 + <Flex align="center" gap="2"> 227 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 228 + <Text size="sm">Payment tracking</Text> 229 + </Flex> 230 + <Flex align="center" gap="2"> 231 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 232 + <Text size="sm">Transaction recording</Text> 233 + </Flex> 234 + <Flex align="center" gap="2"> 235 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 236 + <Text size="sm">Basic reports</Text> 237 + </Flex> 238 + <Flex align="center" gap="2"> 239 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 240 + <Text size="sm">Email support</Text> 241 + </Flex> 242 + </Flex> 243 + <Button variant="outline">Downgrade</Button> 244 + </Flex> 245 + <Flex direction="column" gap="5" style={styles.grow}> 246 + <Flex direction="column" gap="2"> 247 + <Text weight="semibold" size="xl"> 248 + Growth 249 + </Text> 250 + <Text size="sm" variant="secondary"> 251 + 10 team members 252 + </Text> 253 + </Flex> 254 + <Text weight="semibold" size="xl"> 255 + $49<Text variant="secondary">{" / mo"}</Text> 256 + </Text> 257 + <Flex direction="column" gap="2"> 258 + <Flex align="center" gap="2"> 259 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 260 + <Text size="sm">Online payments</Text> 261 + </Flex> 262 + <Flex align="center" gap="2"> 263 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 264 + <Text size="sm">Recurring invoices</Text> 265 + </Flex> 266 + <Flex align="center" gap="2"> 267 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 268 + <Text size="sm">Bill management</Text> 269 + </Flex> 270 + <Flex align="center" gap="2"> 271 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 272 + <Text size="sm">Inventory tracking</Text> 273 + </Flex> 274 + <Flex align="center" gap="2"> 275 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 276 + <Text size="sm">Detailed reports</Text> 277 + </Flex> 278 + <Flex align="center" gap="2"> 279 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 280 + <Text size="sm">Phone support</Text> 281 + </Flex> 282 + </Flex> 283 + <Button variant="outline">Go to billing</Button> 284 + </Flex> 285 + <Flex direction="column" gap="5" style={styles.grow}> 286 + <Flex direction="column" gap="2"> 287 + <Text weight="semibold" size="xl"> 288 + Pro 289 + </Text> 290 + <Text size="sm" variant="secondary"> 291 + Unlimited team members 292 + </Text> 293 + </Flex> 294 + <Text weight="semibold" size="xl"> 295 + $99<Text variant="secondary">{" / mo"}</Text> 296 + </Text> 297 + <Flex direction="column" gap="2"> 298 + <Flex align="center" gap="2"> 299 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 300 + <Text size="sm">Custom invoices</Text> 301 + </Flex> 302 + <Flex align="center" gap="2"> 303 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 304 + <Text size="sm">Multi-business</Text> 305 + </Flex> 306 + <Flex align="center" gap="2"> 307 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 308 + <Text size="sm">Team collaboration</Text> 309 + </Flex> 310 + <Flex align="center" gap="2"> 311 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 312 + <Text size="sm">App integrations</Text> 313 + </Flex> 314 + <Flex align="center" gap="2"> 315 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 316 + <Text size="sm">Advanced security</Text> 317 + </Flex> 318 + <Flex align="center" gap="2"> 319 + <CheckCircle {...stylex.props(styles.check)} size={16} /> 320 + <Text size="sm">Priority support</Text> 321 + </Flex> 322 + </Flex> 323 + <Button>Upgrade</Button> 324 + </Flex> 325 + </Flex> 326 + </CardBody> 327 + </Card> 328 + ); 329 + } 330 + 331 + function Notifications() { 332 + const sections = [ 333 + { 334 + title: "Comments", 335 + description: 336 + "Receive notifications when someone comments on your documents or mentions you.", 337 + }, 338 + { 339 + title: "Favorites", 340 + description: 341 + "Receive notifications when there is activity related to your favorited items.", 342 + }, 343 + { 344 + title: "New documents", 345 + description: 346 + "Receive notifications whenever people on your team create new documents.", 347 + }, 348 + ]; 349 + 350 + return ( 351 + <Card> 352 + <CardHeader> 353 + <CardTitle>Notifications</CardTitle> 354 + <CardDescription>Manage your notification settings.</CardDescription> 355 + </CardHeader> 356 + <CardBody> 357 + <Grid columns="1fr auto" rowGap="6" alignItems="start"> 358 + {sections.map((section, index) => ( 359 + <Fragment key={section.title}> 360 + <Flex direction="column" gap="1"> 361 + <Heading5>{section.title}</Heading5> 362 + <SmallBody variant="secondary">{section.description}</SmallBody> 363 + </Flex> 364 + <Flex direction="column" gap="2"> 365 + <Switch>Push</Switch> 366 + <Switch>Email</Switch> 367 + <Switch isDisabled>Slack</Switch> 368 + </Flex> 369 + {index < sections.length - 1 && ( 370 + <GridItem columnStart={1} columnEnd={-1}> 371 + <Separator /> 372 + </GridItem> 373 + )} 374 + </Fragment> 375 + ))} 376 + </Grid> 377 + </CardBody> 378 + </Card> 379 + ); 380 + } 381 + 382 + function RecentActivity() { 383 + const activities = [ 384 + { 385 + name: "Oliver Chen", 386 + timestamp: "06-08-2025 10:00 AM", 387 + description: ( 388 + <> 389 + Approved invoice <Link href="#">#3461</Link>{" "} 390 + </> 391 + ), 392 + avatar: 393 + "https://images.unsplash.com/photo-1521119989659-a83eee488004?&amp;w=64&amp;h=64&amp;dpr=2&amp;q=70&amp;crop=focalpoint&amp;fp-x=0.45&amp;fp-y=0.37&amp;fp-z=3.5&amp;fit=crop", 394 + }, 395 + { 396 + name: "Amelia Rodriguez", 397 + timestamp: "06-08-2025 10:00 AM", 398 + description: ( 399 + <> 400 + Purchased <Link href="#">15 office chairs</Link>{" "} 401 + </> 402 + ), 403 + avatar: 404 + "https://images.unsplash.com/photo-1632765854612-9b02b6ec2b15?&amp;w=64&amp;h=64&amp;dpr=2&amp;q=70&amp;crop=focalpoint&amp;fp-x=0.4&amp;fp-y=0.35&amp;fp-z=1.05&amp;fit=crop", 405 + }, 406 + { 407 + name: "Theodore Kim", 408 + timestamp: "06-08-2025 10:00 AM", 409 + avatar: 410 + "https://images.unsplash.com/photo-1632765854612-9b02b6ec2b15?&amp;w=64&amp;h=64&amp;dpr=2&amp;q=70&amp;crop=focalpoint&amp;fp-x=0.4&amp;fp-y=0.35&amp;fp-z=1.05&amp;fit=crop", 411 + description: ( 412 + <> 413 + Responded to your commente <Link href="#">#7514</Link>{" "} 414 + </> 415 + ), 416 + }, 417 + { 418 + name: "Jasper Eriksson", 419 + timestamp: "06-08-2025 10:00 AM", 420 + avatar: 421 + "https://images.unsplash.com/photo-1586822339087-80cc375ac083?&amp;w=64&amp;h=64&amp;dpr=2&amp;q=70&amp;crop=focalpoint&amp;fp-x=0.5&amp;fp-y=0.6&amp;fp-z=1&amp;fit=crop", 422 + description: ( 423 + <> 424 + Created <Link href="#">4 invoices</Link>{" "} 425 + </> 426 + ), 427 + }, 428 + { 429 + name: "Travis Ross", 430 + timestamp: "06-08-2025 10:00 AM", 431 + avatar: 432 + "https://images.unsplash.com/photo-1564564321837-a57b7070ac4f?&amp;w=64&amp;h=64&amp;dpr=2&amp;q=70&amp;crop=focalpoint&amp;fp-x=0.52&amp;fp-y=0.47&amp;fp-z=1.3&amp;fit=crop", 433 + description: ( 434 + <> 435 + Updated client details for <Link href="#">Acme Co.</Link>{" "} 436 + </> 437 + ), 438 + }, 439 + { 440 + name: "Gizela Kavková", 441 + timestamp: "06-08-2025 10:00 AM", 442 + avatar: 443 + "https://images.unsplash.com/photo-1525304937537-4d586f394674?&amp;w=64&amp;h=64&amp;dpr=2&amp;q=70&amp;crop=faces&amp;fit=crop", 444 + description: ( 445 + <> 446 + Created <Link href="#">4 invoices</Link>{" "} 447 + </> 448 + ), 449 + }, 450 + { 451 + name: "Gizela Kavková", 452 + timestamp: "06-08-2025 8:00 AM", 453 + avatar: 454 + "https://images.unsplash.com/photo-1525304937537-4d586f394674?&amp;w=64&amp;h=64&amp;dpr=2&amp;q=70&amp;crop=faces&amp;fit=crop", 455 + description: ( 456 + <> 457 + Deleted report <Link href="#">#1234</Link>{" "} 458 + </> 459 + ), 460 + }, 461 + { 462 + name: "Da-Xia Wu", 463 + timestamp: "06-08-2025 8:00 AM", 464 + avatar: 465 + "https://images.unsplash.com/photo-1541823709867-1b206113eafd?&amp;w=64&amp;h=64&amp;dpr=2&amp;q=70&amp;crop=focalpoint&amp;fp-x=0.5&amp;fp-y=0.3&amp;fp-z=1.5&amp;fit=crop", 466 + description: <>Joined the team</>, 467 + }, 468 + ]; 469 + 470 + return ( 471 + <Card style={styles.relative}> 472 + <CardHeader> 473 + <CardTitle>Recent activity</CardTitle> 474 + <CardDescription> 475 + Review what has happened over the past days. 476 + </CardDescription> 477 + </CardHeader> 478 + <CardBody> 479 + <Grid 480 + columns="auto 1fr auto" 481 + columnGap="4" 482 + rowGap="5" 483 + alignItems="center" 484 + > 485 + {activities.map((activity, index) => ( 486 + <Fragment key={activity.timestamp}> 487 + <Avatar 488 + size="lg" 489 + src={activity.avatar} 490 + fallback={activity.name.charAt(0)} 491 + /> 492 + <Flex direction="column" gap="2"> 493 + <Text weight="medium">{activity.name}</Text> 494 + <SmallBody variant="secondary"> 495 + {activity.description} 496 + </SmallBody> 497 + </Flex> 498 + <SmallBody variant="secondary"> 499 + {Intl.DateTimeFormat("en-US", { 500 + dateStyle: "short", 501 + timeStyle: "short", 502 + }).format(new Date(activity.timestamp))} 503 + </SmallBody> 504 + {index < activities.length - 1 && ( 505 + <GridItem columnStart={1} columnEnd={-1}> 506 + <Separator /> 507 + </GridItem> 508 + )} 509 + </Fragment> 510 + ))} 511 + </Grid> 512 + <Flex gap="1" style={styles.pinnedButtons}> 513 + <IconButton variant="tertiary" label="Open in new tab"> 514 + <ExternalLink /> 515 + </IconButton> 516 + <ToggleButton defaultSelected variant="tertiary"> 517 + <Pin /> 518 + </ToggleButton> 519 + </Flex> 520 + </CardBody> 521 + </Card> 522 + ); 523 + } 524 + 525 + function FinancialPerformance() { 526 + const data = [ 527 + { 528 + label: "MRR", 529 + change: "3.2%", 530 + value: "$350K", 531 + trend: "positive", 532 + direction: "up", 533 + }, 534 + { 535 + label: "OpEx", 536 + change: "12.8%", 537 + value: "$211K", 538 + trend: "negative", 539 + direction: "up", 540 + }, 541 + { 542 + label: "CapEx", 543 + change: "8.8%", 544 + value: "$94K", 545 + trend: "positive", 546 + direction: "down", 547 + }, 548 + { 549 + label: "GPM", 550 + change: "1.2%", 551 + value: "44.6%", 552 + trend: "negative", 553 + direction: "down", 554 + }, 555 + { 556 + label: "NPM", 557 + change: "0.0%", 558 + value: "9.1%", 559 + trend: "neutral", 560 + direction: "none", 561 + }, 562 + { 563 + label: "EBITDA", 564 + change: "4.1%", 565 + value: "$443K", 566 + trend: "positive", 567 + direction: "up", 568 + }, 569 + { 570 + label: "CAC", 571 + change: "11.0%", 572 + value: "$146", 573 + trend: "positive", 574 + direction: "down", 575 + }, 576 + { 577 + label: "LTV", 578 + change: "3%", 579 + value: "$1,849", 580 + trend: "positive", 581 + direction: "up", 582 + }, 583 + { 584 + label: "Churn", 585 + change: "1.1%", 586 + value: "12.4%", 587 + trend: "negative", 588 + direction: "up", 589 + }, 590 + ]; 591 + 592 + return ( 593 + <Card style={styles.relative}> 594 + <CardHeader> 595 + <CardTitle>Financial performance</CardTitle> 596 + <CardDescription> 597 + Review your company's KPIs compared to the month before. . 598 + </CardDescription> 599 + </CardHeader> 600 + <CardBody> 601 + <Grid 602 + columns="1fr 1fr 1fr" 603 + columnGap="10" 604 + rowGap="10" 605 + alignItems="center" 606 + > 607 + {data.map((item) => ( 608 + <Flex 609 + key={`${item.label}-${item.change}`} 610 + direction="column" 611 + gap="4" 612 + > 613 + <Flex gap="2" align="center"> 614 + <Text variant="secondary">{item.label}</Text> 615 + <Badge 616 + size="sm" 617 + variant={ 618 + item.trend === "positive" 619 + ? "success" 620 + : item.trend === "negative" 621 + ? "critical" 622 + : "default" 623 + } 624 + > 625 + {item.direction === "up" && <ArrowUp />} 626 + {item.direction === "down" && <ArrowDown />} 627 + {item.change} 628 + </Badge> 629 + </Flex> 630 + <Text size="3xl" weight="semibold"> 631 + {item.value} 632 + </Text> 633 + </Flex> 634 + ))} 635 + </Grid> 636 + <Flex gap="1" style={styles.pinnedButtons}> 637 + <IconButton variant="tertiary" label="Open in new tab"> 638 + <ExternalLink /> 639 + </IconButton> 640 + <ToggleButton defaultSelected variant="tertiary"> 641 + <Pin /> 642 + </ToggleButton> 643 + </Flex> 644 + </CardBody> 645 + </Card> 646 + ); 647 + } 648 + 649 + function Todos() { 650 + const todos = [ 651 + { 652 + id: "1", 653 + title: ( 654 + <span> 655 + Respond to comment <Link>#384</Link> from Travis Ross 656 + </span> 657 + ), 658 + completed: false, 659 + }, 660 + { 661 + id: "2", 662 + title: <span>Invite Acme Co. team to Slack</span>, 663 + completed: false, 664 + }, 665 + { 666 + id: "3", 667 + title: <span>Create a report requested by Danilo Sousa</span>, 668 + completed: false, 669 + }, 670 + { 671 + id: "4", 672 + title: ( 673 + <span> 674 + Review support request <Link>#85</Link> 675 + </span> 676 + ), 677 + completed: false, 678 + }, 679 + { id: "5", title: <span>Close Q2 finances</span>, completed: true }, 680 + { 681 + id: "6", 682 + title: ( 683 + <span> 684 + Review invoice <Link>#3456</Link> 685 + </span> 686 + ), 687 + completed: true, 688 + }, 689 + ]; 690 + 691 + return ( 692 + <Card style={styles.relative}> 693 + <CardHeader> 694 + <CardTitle>To-do</CardTitle> 695 + <CardDescription>Stay on top of your daily tasks.</CardDescription> 696 + </CardHeader> 697 + <CardBody> 698 + <Flex direction="column" gap="4"> 699 + {todos.map((todo) => ( 700 + <Checkbox isSelected={todo.completed} key={todo.id}> 701 + <Text strikethrough={todo.completed}>{todo.title}</Text> 702 + </Checkbox> 703 + ))} 704 + </Flex> 705 + <Flex gap="1" style={styles.pinnedButtons}> 706 + <IconButton variant="tertiary" label="Share tasks"> 707 + <Share /> 708 + </IconButton> 709 + <IconButton variant="tertiary" label="Add new task"> 710 + <Plus /> 711 + </IconButton> 712 + </Flex> 713 + </CardBody> 714 + </Card> 715 + ); 716 + } 717 + 718 + function SignUpForm() { 719 + return ( 720 + <Card> 721 + <CardHeader> 722 + <CardTitle>Sign Up</CardTitle> 723 + </CardHeader> 724 + <CardBody> 725 + <Flex direction="column" gap="4"> 726 + <TextField label="Email Address" type="email" /> 727 + <TextField 728 + type="password" 729 + label={ 730 + <Flex justify="between" align="center"> 731 + <span>Password</span> 732 + <Link style={typeramp.sublabel}>Forgot Password?</Link> 733 + </Flex> 734 + } 735 + /> 736 + </Flex> 737 + </CardBody> 738 + <CardFooter> 739 + <Button variant="secondary">Create Account</Button> 740 + <Button>Sign In</Button> 741 + </CardFooter> 742 + </Card> 743 + ); 744 + } 745 + 746 + function SampleInvoice() { 747 + return ( 748 + <Card style={styles.relative}> 749 + <CardHeader> 750 + <CardTitle> 751 + Invoice <Link>#3461</Link> 752 + </CardTitle> 753 + </CardHeader> 754 + <CardBody> 755 + <Flex direction="column" gap="8"> 756 + <Grid columns="1fr 1fr" columnGap="6"> 757 + <Flex direction="column" gap="2"> 758 + <Text size="sm" variant="secondary"> 759 + Issued 760 + </Text> 761 + <Text weight="medium">June 21, 2023</Text> 762 + </Flex> 763 + <Flex direction="column" gap="2"> 764 + <Text size="sm" variant="secondary"> 765 + Due 766 + </Text> 767 + <Text weight="medium">July 21, 2023</Text> 768 + </Flex> 769 + <Flex direction="column" gap="2"> 770 + <Text size="sm" variant="secondary"> 771 + To 772 + </Text> 773 + <Text weight="medium">Paradise Ventures</Text> 774 + <Text size="sm"> 775 + 742 Evergreen Terrace, Springfield, IL 62704 776 + </Text> 777 + </Flex> 778 + <Flex direction="column" gap="2"> 779 + <Text size="sm" variant="secondary"> 780 + From 781 + </Text> 782 + <Text weight="medium">Rogue Widgets</Text> 783 + <Text size="sm">1600 Baker Street NW, Washington, DC 20500</Text> 784 + </Flex> 785 + </Grid> 786 + 787 + <Flex direction="column" gap="4"> 788 + <Flex justify="between" align="center"> 789 + <Text size="sm" variant="secondary"> 790 + Services 791 + </Text> 792 + <Text size="sm" variant="secondary"> 793 + Price 794 + </Text> 795 + </Flex> 796 + <Flex justify="between" align="center"> 797 + <Text weight="medium" size="lg"> 798 + Branding 799 + </Text> 800 + <Text>$20,000</Text> 801 + </Flex> 802 + <Flex justify="between" align="center"> 803 + <Text weight="medium" size="lg"> 804 + Marketing website 805 + </Text> 806 + <Text>$17,500</Text> 807 + </Flex> 808 + <Separator /> 809 + <Flex justify="between" align="center"> 810 + <Text>Total</Text> 811 + <Text>$37,500</Text> 812 + </Flex> 813 + </Flex> 814 + </Flex> 815 + <Flex gap="1" style={styles.pinnedButtons}> 816 + <IconButton variant="tertiary" label="Close"> 817 + <X /> 818 + </IconButton> 819 + </Flex> 820 + </CardBody> 821 + <CardFooter> 822 + <Button variant="critical-outline">Reject</Button> 823 + <Button>Approve</Button> 824 + </CardFooter> 825 + </Card> 826 + ); 827 + } 828 + 829 + function InvoicePaid() { 830 + return ( 831 + <Card style={[styles.relative, styles.invoiceCard]}> 832 + <Flex direction="column" gap="6" style={styles.textCenter}> 833 + <Flex align="center" justify="center"> 834 + <CheckCircle2 size={48} {...stylex.props(styles.check)} /> 835 + </Flex> 836 + <Text size="xl" weight="medium"> 837 + Invoice paid 838 + </Text> 839 + <Body> 840 + You paid $17,975.30. A receipt copy was sent to{" "} 841 + <Text weight="semibold">accounting@example.com</Text> 842 + </Body> 843 + <Flex direction="column" gap="2"> 844 + <Button>Next invoice</Button> 845 + <Button variant="outline">Done</Button> 846 + </Flex> 847 + </Flex> 848 + <Flex gap="1" style={styles.pinnedButtons}> 849 + <IconButton variant="tertiary" label="Close"> 850 + <X /> 851 + </IconButton> 852 + </Flex> 853 + </Card> 854 + ); 855 + } 856 + 857 + function YourCompanyCard() { 858 + return ( 859 + <Card> 860 + <CardHeader> 861 + <CardTitle>Your Company Card</CardTitle> 862 + <CardDescription>View and manage your corporate card.</CardDescription> 863 + </CardHeader> 864 + <CardBody> 865 + <div 866 + {...stylex.props( 867 + styles.creditCardWrapper, 868 + gray.bgDim, 869 + primary.textContrast, 870 + )} 871 + > 872 + <Flex 873 + direction="column" 874 + justify="between" 875 + gap="2" 876 + style={styles.creditCard} 877 + > 878 + <Text>Shane Goodall</Text> 879 + <Flex direction="column" gap="2"> 880 + <Flex align="center" gap="2"> 881 + <Text>1234 5678 9012 3456</Text> 882 + <IconButton 883 + size="sm" 884 + variant="tertiary" 885 + label="Copy card number" 886 + style={styles.copyCardNumber} 887 + > 888 + <Copy /> 889 + </IconButton> 890 + </Flex> 891 + <Flex align="center" gap="2"> 892 + <Text>01/27</Text> 893 + <Text>999</Text> 894 + </Flex> 895 + </Flex> 896 + </Flex> 897 + </div> 898 + </CardBody> 899 + <CardFooter> 900 + <Button variant="critical-outline">Freeze</Button> 901 + <Button>Done</Button> 902 + </CardFooter> 903 + </Card> 904 + ); 905 + } 906 + 125 907 function RouteComponent() { 126 908 return ( 127 - <div> 128 - <YourTeam /> 129 - </div> 909 + <Flex gap="6"> 910 + <Flex direction="column" gap="6" style={styles.grow}> 911 + <YourTeam /> 912 + <Notifications /> 913 + <Pricing /> 914 + </Flex> 915 + <Flex direction="column" gap="6" style={styles.skinny}> 916 + <SignUpForm /> 917 + <YourCompanyCard /> 918 + <InvoicePaid /> 919 + <SampleInvoice /> 920 + </Flex> 921 + <Flex direction="column" gap="6" style={styles.grow}> 922 + <FinancialPerformance /> 923 + <RecentActivity /> 924 + <Todos /> 925 + </Flex> 926 + </Flex> 130 927 ); 131 928 }
+2
packages/hip-ui/src/cli/install.tsx
··· 34 34 import { searchFieldConfig } from "../components/search-field/search-field-config.js"; 35 35 import { selectConfig } from "../components/select/select-config.js"; 36 36 import { separatorConfig } from "../components/separator/separator-config.js"; 37 + import { switchConfig } from "../components/switch/switch-config.js"; 37 38 import { textAreaConfig } from "../components/text-area/text-area-config.js"; 38 39 import { textFieldConfig } from "../components/text-field/text-field-config.js"; 39 40 import { timeFieldConfig } from "../components/time-field/time-field-config.js"; ··· 82 83 avatarConfig, 83 84 badgeConfig, 84 85 gridConfig, 86 + switchConfig, 85 87 ]; 86 88 87 89 function StringSetting({
+11 -3
packages/hip-ui/src/components/card/index.tsx
··· 13 13 flexDirection: "column", 14 14 fontFamily: fontFamily["sans"], 15 15 gap: spacing["6"], 16 - width: "fit-content", 17 16 }, 18 17 cardHeader: { 19 18 paddingBottom: { ":last-child": spacing["4"] }, ··· 22 21 paddingTop: spacing["5"], 23 22 }, 24 23 cardTitle: { 25 - fontSize: fontSize["lg"], 24 + fontSize: fontSize["xl"], 26 25 fontWeight: fontWeight["bold"], 27 26 }, 28 27 cardDescription: { ··· 31 30 margin: 0, 32 31 }, 33 32 cardBody: { 33 + display: "flex", 34 + flexDirection: "column", 35 + gap: spacing["6"], 34 36 paddingBottom: { ":last-child": spacing["4"] }, 35 37 paddingLeft: spacing["4"], 36 38 paddingRight: spacing["4"], ··· 55 57 return ( 56 58 <div 57 59 {...props} 58 - {...stylex.props(styles.card, gray.bgSubtle, gray.border, style)} 60 + {...stylex.props( 61 + styles.card, 62 + gray.bgSubtle, 63 + gray.border, 64 + gray.text, 65 + style, 66 + )} 59 67 /> 60 68 ); 61 69 };
+73
packages/hip-ui/src/components/switch/index.tsx
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + import { 3 + SwitchProps as AriaSwitchProps, 4 + Switch as AriaSwitch, 5 + } from "react-aria-components"; 6 + 7 + import { plum, slate } from "../theme/colors.stylex"; 8 + import { radius } from "../theme/radius.stylex"; 9 + import { shadow } from "../theme/shadow.stylex"; 10 + import { spacing } from "../theme/spacing.stylex"; 11 + import { typeramp } from "../theme/typography.stylex"; 12 + 13 + const styles = stylex.create({ 14 + wrapper: { 15 + alignItems: "center", 16 + display: "flex", 17 + gap: spacing["2"], 18 + }, 19 + indicator: { 20 + backgroundColor: { 21 + default: slate.component3, 22 + ":is([data-selected=true] *)": plum.solid1, 23 + }, 24 + borderRadius: radius.full, 25 + height: spacing["6"], 26 + opacity: { 27 + default: 1, 28 + ":is([data-disabled=true] *)": 0.5, 29 + }, 30 + position: "relative", 31 + transitionDuration: "100ms", 32 + transitionProperty: "background-color", 33 + transitionTimingFunction: "ease-in-out", 34 + width: spacing["10"], 35 + }, 36 + thumb: { 37 + backgroundColor: slate.bg2, 38 + borderRadius: radius.full, 39 + boxShadow: shadow.lg, 40 + content: "''", 41 + height: spacing["4"], 42 + left: 0, 43 + marginLeft: spacing["1"], 44 + marginRight: spacing["1"], 45 + position: "absolute", 46 + top: "50%", 47 + transform: { 48 + default: "translateY(-50%)", 49 + ":is([data-selected=true] *)": "translate(100%, -50%)", 50 + }, 51 + transitionDuration: "100ms", 52 + transitionProperty: "transform", 53 + transitionTimingFunction: "ease-in-out", 54 + width: spacing["4"], 55 + }, 56 + }); 57 + 58 + export interface SwitchProps 59 + extends Omit<AriaSwitchProps, "children" | "style" | "className"> { 60 + style?: stylex.StyleXStyles | stylex.StyleXStyles[]; 61 + children: React.ReactNode; 62 + } 63 + 64 + export function Switch({ children, style, ...props }: SwitchProps) { 65 + return ( 66 + <AriaSwitch {...props} {...stylex.props(styles.wrapper, style)}> 67 + <div {...stylex.props(styles.indicator)}> 68 + <div {...stylex.props(styles.thumb)} /> 69 + </div> 70 + <div {...stylex.props(typeramp.label)}>{children}</div> 71 + </AriaSwitch> 72 + ); 73 + }
+15
packages/hip-ui/src/components/switch/switch-config.ts
··· 1 + import { ComponentConfig } from "../../types"; 2 + 3 + export const switchConfig: ComponentConfig = { 4 + name: "switch", 5 + filepath: "./index.tsx", 6 + hipDependencies: [ 7 + "../theme/spacing.stylex.tsx", 8 + "../theme/colors.stylex.tsx", 9 + "../theme/radius.stylex.tsx", 10 + "../theme/semantic-color.stylex.tsx", 11 + "../theme/typography.stylex.tsx", 12 + "../theme/breakpoints.stylex.tsx", 13 + "../theme/shadow.stylex.tsx", 14 + ], 15 + };
+3 -1
packages/hip-ui/src/components/theme/spacing.stylex.tsx
··· 1 1 import * as stylex from "@stylexjs/stylex"; 2 2 3 + import { ThemeKeys } from "./types"; 4 + 3 5 export const spacing = stylex.defineVars({ 4 6 px: "1px", 5 7 "0": "0px", ··· 39 41 }); 40 42 41 43 // eslint-disable-next-line @stylexjs/enforce-extension 42 - export type Spacing = keyof typeof spacing; 44 + export type Spacing = ThemeKeys<typeof spacing>;
+4
packages/hip-ui/src/components/theme/types.ts
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + 3 + export type ThemeKeys<T> = 4 + T extends stylex.VarGroup<Readonly<infer Tokens>> ? keyof Tokens : never;
+3 -1
packages/hip-ui/src/components/theme/typography.stylex.tsx
··· 4 4 import { spacing } from "./spacing.stylex"; 5 5 6 6 export const fontFamily = stylex.defineVars({ 7 - sans: "Inter, sans-serif", 7 + sans: "'Inter', sans-serif", 8 8 serif: "Georgia, serif", 9 9 mono: "Monaco, monospace", 10 10 }); ··· 131 131 fontWeight: fontWeight["semibold"], 132 132 letterSpacing: tracking["tight"], 133 133 lineHeight: { default: lineHeight["lg"] }, 134 + margin: 0, 135 + scrollMarginBlockStart: spacing["20"], 134 136 }, 135 137 body: { 136 138 // eslint-disable-next-line @stylexjs/valid-styles
+6 -4
packages/hip-ui/src/components/theme/useButtonStyles.ts
··· 90 90 }, 91 91 paddingRight: spacing["4"], 92 92 }, 93 - outline: { 94 - borderWidth: 1, 95 - }, 96 93 secondary: { 97 94 borderColor: { 98 95 default: slate.component1, ··· 168 165 gray.borderInteractive, 169 166 gray.bgGhost, 170 167 gray.text, 171 - styles.outline, 172 168 styles.shadow, 173 169 ], 174 170 variant === "critical" && [ 175 171 critical.bgSolidAction, 176 172 critical.borderInteractive, 177 173 critical.textContrast, 174 + styles.shadow, 175 + ], 176 + variant === "critical-outline" && [ 177 + critical.borderInteractive, 178 + critical.bgGhost, 179 + critical.text, 178 180 styles.shadow, 179 181 ], 180 182 size === "sm" && styles.small,
+7
packages/hip-ui/src/components/toggle-button/index.tsx
··· 56 56 ":active": slate.border3, 57 57 }, 58 58 }, 59 + "critical-outlineSelected": { 60 + backgroundColor: { 61 + default: slate.border1, 62 + ":hover": slate.border2, 63 + ":active": slate.border3, 64 + }, 65 + }, 59 66 sm: { 60 67 paddingLeft: { 61 68 ":has(> * + *, > *:not(svg):only-child)": spacing["2"],
+2 -1
packages/hip-ui/src/components/types.ts
··· 4 4 | "secondary" 5 5 | "tertiary" 6 6 | "outline" 7 - | "critical"; 7 + | "critical" 8 + | "critical-outline";
+36 -8
packages/hip-ui/src/components/typography/index.tsx
··· 97 97 return <h4 {...stylex.props(typeramp.heading4, style)} {...props} />; 98 98 }; 99 99 100 + export interface Heading5Props 101 + extends Omit<React.ComponentProps<"h5">, "style" | "className"> { 102 + style?: stylex.StyleXStyles | stylex.StyleXStyles[]; 103 + } 104 + 105 + export const Heading5 = ({ style, ...props }: Heading5Props) => { 106 + // eslint-disable-next-line jsx-a11y/heading-has-content 107 + return <h5 {...stylex.props(typeramp.heading5, style)} {...props} />; 108 + }; 109 + 100 110 export interface BodyProps 101 111 extends Omit<React.ComponentProps<"p">, "style" | "className"> { 102 112 style?: stylex.StyleXStyles | stylex.StyleXStyles[]; ··· 129 139 variant = "default", 130 140 ...props 131 141 }: SmallBodyProps) => { 142 + const contextValue = useMemo( 143 + () => ({ 144 + style: [variant === "secondary" && gray.textDim, styles.underline], 145 + }), 146 + [variant], 147 + ); 148 + 132 149 return ( 133 - <p 134 - {...stylex.props( 135 - typeramp.smallBody, 136 - variant === "secondary" && gray.textDim, 137 - style, 138 - )} 139 - {...props} 140 - /> 150 + <LinkContext value={contextValue}> 151 + <p 152 + {...stylex.props( 153 + typeramp.smallBody, 154 + variant === "secondary" && gray.textDim, 155 + style, 156 + )} 157 + {...props} 158 + /> 159 + </LinkContext> 141 160 ); 161 + }; 162 + 163 + interface LabelTextProps 164 + extends Omit<React.ComponentProps<"p">, "style" | "className"> { 165 + style?: stylex.StyleXStyles | stylex.StyleXStyles[]; 166 + } 167 + 168 + export const LabelText = ({ style, ...props }: LabelTextProps) => { 169 + return <p {...stylex.props(typeramp.label, style)} {...props} />; 142 170 }; 143 171 144 172 interface SubLabelProps
+109
packages/hip-ui/src/components/typography/text.tsx
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + 3 + import { red, slate } from "../theme/colors.stylex"; 4 + import { ThemeKeys } from "../theme/types"; 5 + import { 6 + fontFamily, 7 + fontSize, 8 + fontWeight, 9 + lineHeight, 10 + tracking, 11 + } from "../theme/typography.stylex"; 12 + 13 + const styles = stylex.create({ 14 + sans: { fontFamily: fontFamily["sans"] }, 15 + serif: { fontFamily: fontFamily["serif"] }, 16 + mono: { fontFamily: fontFamily["mono"] }, 17 + 18 + thin: { fontWeight: fontWeight["thin"] }, 19 + extralight: { fontWeight: fontWeight["extralight"] }, 20 + light: { fontWeight: fontWeight["light"] }, 21 + normal: { fontWeight: fontWeight["normal"] }, 22 + medium: { fontWeight: fontWeight["medium"] }, 23 + semibold: { fontWeight: fontWeight["semibold"] }, 24 + bold: { fontWeight: fontWeight["bold"] }, 25 + extrabold: { fontWeight: fontWeight["extrabold"] }, 26 + black: { fontWeight: fontWeight["black"] }, 27 + 28 + "font-xs": { fontSize: fontSize["xs"] }, 29 + "font-sm": { fontSize: fontSize["sm"] }, 30 + "font-base": { fontSize: fontSize["base"] }, 31 + "font-lg": { fontSize: fontSize["lg"] }, 32 + "font-xl": { fontSize: fontSize["xl"] }, 33 + "font-2xl": { fontSize: fontSize["2xl"] }, 34 + "font-3xl": { fontSize: fontSize["3xl"] }, 35 + "font-4xl": { fontSize: fontSize["4xl"] }, 36 + "font-5xl": { fontSize: fontSize["5xl"] }, 37 + "font-6xl": { fontSize: fontSize["6xl"] }, 38 + "font-7xl": { fontSize: fontSize["7xl"] }, 39 + "font-8xl": { fontSize: fontSize["8xl"] }, 40 + "font-9xl": { fontSize: fontSize["9xl"] }, 41 + 42 + "leading-none": { lineHeight: lineHeight["none"] }, 43 + "leading-xs": { lineHeight: lineHeight["xs"] }, 44 + "leading-sm": { lineHeight: lineHeight["sm"] }, 45 + "leading-base": { lineHeight: lineHeight["base"] }, 46 + "leading-lg": { lineHeight: lineHeight["lg"] }, 47 + "leading-xl": { lineHeight: lineHeight["xl"] }, 48 + "leading-2xl": { lineHeight: lineHeight["2xl"] }, 49 + "leading-3xl": { lineHeight: lineHeight["3xl"] }, 50 + "leading-4xl": { lineHeight: lineHeight["4xl"] }, 51 + "leading-5xl": { lineHeight: lineHeight["5xl"] }, 52 + "leading-6xl": { lineHeight: lineHeight["6xl"] }, 53 + "leading-7xl": { lineHeight: lineHeight["7xl"] }, 54 + "leading-8xl": { lineHeight: lineHeight["8xl"] }, 55 + "leading-9xl": { lineHeight: lineHeight["9xl"] }, 56 + 57 + "tracking-tighter": { letterSpacing: tracking["tighter"] }, 58 + "tracking-tight": { letterSpacing: tracking["tight"] }, 59 + "tracking-normal": { letterSpacing: tracking["normal"] }, 60 + "tracking-wide": { letterSpacing: tracking["wide"] }, 61 + "tracking-wider": { letterSpacing: tracking["wider"] }, 62 + "tracking-widest": { letterSpacing: tracking["widest"] }, 63 + 64 + "variant-primary": { color: slate.text2 }, 65 + "variant-secondary": { color: slate.text1 }, 66 + "variant-destructive": { color: red.text2 }, 67 + 68 + strikethrough: { textDecoration: "line-through" }, 69 + }); 70 + 71 + interface TextProps 72 + extends Omit<React.ComponentProps<"span">, "style" | "className"> { 73 + style?: stylex.StyleXStyles | stylex.StyleXStyles[]; 74 + font?: ThemeKeys<typeof fontFamily>; 75 + weight?: ThemeKeys<typeof fontWeight>; 76 + size?: ThemeKeys<typeof fontSize>; 77 + leading?: ThemeKeys<typeof lineHeight>; 78 + tracking?: ThemeKeys<typeof tracking>; 79 + variant?: "primary" | "secondary" | "destructive"; 80 + strikethrough?: boolean; 81 + } 82 + 83 + export const Text = ({ 84 + style, 85 + font = "sans", 86 + weight, 87 + size, 88 + leading, 89 + tracking, 90 + variant, 91 + strikethrough = false, 92 + ...props 93 + }: TextProps) => { 94 + return ( 95 + <span 96 + {...stylex.props( 97 + styles[font], 98 + weight && styles[weight], 99 + size && styles[`font-${size}`], 100 + leading && styles[`leading-${leading}`], 101 + tracking && styles[`tracking-${tracking}`], 102 + variant && styles[`variant-${variant}`], 103 + strikethrough && styles.strikethrough, 104 + style, 105 + )} 106 + {...props} 107 + /> 108 + ); 109 + };
+2
packages/hip-ui/src/components/typography/typography-config.ts
··· 10 10 "../theme/spacing.stylex.tsx", 11 11 "../theme/typography.stylex.tsx", 12 12 "../link/link-context.ts", 13 + "../theme/types.ts", 14 + "./text.tsx", 13 15 ], 14 16 };