Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(opportunity): new hero, tableRow, OpportunityFilters #21

Merged
merged 3 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/extenders/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function Modal({ state, title, description, modal, children, clas
<Dialog.Content
style={vars}
className={mergeClass("fixed top-1/2 left-1/2 z-50 -translate-x-1/2 -translate-y-1/2", className)}>
<Box size="xl" className="!p-md*4 lg:!p-lg*4 shadow-md" {...props}>
<Box size="xl" className="p-lg*4 shadow-md" {...props}>
{title && (
<Dialog.Title asChild={!!title}>
{typeof title === "string" ? <Title h={3}>{title}</Title> : title}
Expand Down
125 changes: 73 additions & 52 deletions src/components/primitives/Box.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,85 @@
/**
* Box Component
*
* A flexible container component that serves as a fundamental building block for layouts.
* It provides various visual styles and sizing options through variants.
*
* @variants
* content:
* - xs to xl: Content size variants
*
* container:
* - true/false: Controls container behavior
*
* @compoundVariants
* The component uses compound variants to determine border radius (rounded corners):
* - When container=true: Uses both size and content values (rounded-${size}+${content})
* - When container=false: Uses only size value (rounded-${size})
*
* @example
* <Box look="soft" size="md" content="sm" container={true}>
* Content goes here
* </Box>
*/

import { tv } from "tailwind-variants";
import useThemedVariables from "../../hooks/theming/useThemedVariables";
import { mergeClass } from "../../utils/css";
import { sizeScale } from "../../utils/tailwind";
import type { Component, Styled, Themable } from "../../utils/types";

export const boxStyles = tv(
{
base: "flex flex-col border-1",
variants: {
look: {
soft: "bg-main-1 border-main-0",
base: "bg-main-3 border-main-0 text-main-12",
bold: "bg-main-2 border-main-6 text-main-12",
tint: "bg-accent-4 border-main-0 text-main-12",
hype: "bg-accent-4 border-accent-6 text-main-12",
},
size: {
xs: "p-xs gap-xs",
sm: "p-sm gap-sm",
md: "p-md gap-md",
lg: "p-lg gap-md",
xl: "p-xl gap-xl",
},
container: {
true: "",
false: "",
},
content: {
xs: "",
sm: "",
md: "",
lg: "",
xl: "",
},
export const boxStyles = tv({
base: "flex flex-col border-1",
variants: {
look: {
soft: "bg-main-1 border-main-0",
base: "bg-main-3 border-main-0 text-main-12",
bold: "bg-main-2 border-main-6 text-main-12",
tint: "bg-accent-4 border-main-0 text-main-12",
hype: "bg-accent-4 border-accent-6 text-main-12",
},
defaultVariants: {
size: "md",
content: "md",
look: "base",
container: true,
size: {
xs: "p-xs gap-xs",
sm: "p-sm gap-sm",
md: "p-md gap-md",
lg: "p-lg gap-md",
xl: "p-xl gap-xl",
},
compoundVariants: sizeScale.flatMap(size =>
sizeScale.flatMap(content => [
{
size,
content,
container: true as const,
class: `rounded-${size}+${content}` as `rounded-${typeof size}+${typeof content}`,
},
{
size,
content,
container: false as const,
class: `rounded-${size}` as `rounded-${typeof size}`,
},
]),
),
container: {
true: "",
false: "",
},
content: {
xs: "",
sm: "",
md: "",
lg: "",
xl: "",
},
},
defaultVariants: {
size: "md",
content: "md",
look: "base",
container: true,
},
{ twMerge: false },
);
compoundVariants: sizeScale.flatMap(size =>
sizeScale.flatMap(content => [
{
size,
content,
container: true as const,
class: `rounded-${size}+${content}` as `rounded-${typeof size}+${typeof content}`,
},
{
size,
content,
container: false as const,
class: `rounded-${size}` as `rounded-${typeof size}`,
},
]),
),
});

export type BoxProps = Component<Styled<typeof boxStyles> & Themable>;

Expand Down
17 changes: 10 additions & 7 deletions src/components/primitives/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import * as RemixIcon from "@remixicon/react";
import { type ReactElement, useMemo } from "react";
import { tv } from "tailwind-variants";
import { mergeClass } from "../..";
import type { Component, Styled } from "../..";
import type { Component, Styled, Themable } from "../..";
import useThemableProps from "../../hooks/theming/useThemableProps";
import Image from "./Image";

export const iconStyles = tv({
base: "flex flex-col border-0 overflow-hidden self-center rounded-sm w-[1em] h-[1em]",
base: "flex flex-col border-0 overflow-hidden self-center rounded-sm w-[1em] h-[1em]",
variants: {
size: {
xs: "",
Expand All @@ -26,20 +27,22 @@ export const iconStyles = tv({
});

export type IconProps = Component<
Styled<typeof iconStyles> & {
src?: string;
remix?: keyof typeof RemixIcon;
},
Styled<typeof iconStyles> &
Themable & {
src?: string;
remix?: keyof typeof RemixIcon;
},
HTMLImageElement
>;

export default function Icon({ rounded, remix, size, src, alt, className, ...props }: IconProps) {
const themeVars = useThemableProps(props);
const styles = useMemo(() => iconStyles({ rounded, size }), [rounded, size]);

const Component = useMemo(() => {
if (remix) return RemixIcon[remix] as () => ReactElement;
return (imageProps: Component<unknown>) => <Image alt={alt} src={src} {...imageProps} />;
}, [remix, alt, src]);

return <Component {...props} className={mergeClass(styles, className)} />;
return <Component {...props} style={themeVars} className={mergeClass(styles, className)} />;
}
20 changes: 10 additions & 10 deletions src/components/primitives/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@ import type { Component, GetSet, Styled } from "../../utils/types";
import Group from "../extenders/Group";

export const inputStyles = tv({
base: "text-main-12 flex items-center text-nowrap font-text",
base: "flex items-center placeholder:text-main-11 text-nowrap font-text",
variants: {
look: {
none: "bg-main-0 border-0",
soft: "bg-main-2 border-main-2 hover:border-main-4 active:border-main-7 hover:text-main-12 focus-within:outline focus-within:outline-main-12",
base: "bg-main-6 focus-within:outline focus-within:outline-main-12",
bold: "bg-main-3 border-main-4 hover:border-main-4 active:border-main-7 hover:text-main-12 focus-within:outline focus-within:outline-main-12",
tint: "bg-main-1 border-accent-6 hover:border-accent-8 active:bg-main-2 text-main-12 focus-within:outline focus-within:outline-main-12",
hype: "bg-main-0 border-accent-8 hover:border-accent-10 active:border-accent-8 hover:text-main-12 focus-within:outline focus-within:outline-main-12",
none: "text-main-12 bg-main-0 border-0",
soft: "text-main-11 bg-main-0 border-main-9 border-1 active:border-main-7 focus-within:outline focus-within:outline-main-12",
base: "text-main-12 bg-main-6 focus-within:outline focus-within:outline-main-12",
bold: "text-main-12 bg-main-3 border-main-4 hover:border-main-4 active:border-main-7 hover:text-main-12 focus-within:outline focus-within:outline-main-12",
tint: "text-main-12 bg-main-1 border-accent-6 hover:border-accent-8 active:bg-main-2 focus-within:outline focus-within:outline-main-12",
hype: "text-main-12 bg-main-0 border-accent-8 hover:border-accent-10 active:border-accent-8 hover:text-main-12 focus-within:outline focus-within:outline-main-12",
},
size: {
xs: "px-xs py-xs text-xs rounded-xs",
sm: "px-sm py-sm text-sm rounded-sm",
md: "px-md py-md text-md rounded-md",
lg: "px-lg py-lg text-lg rounded-lg",
xl: "px-xl py-xl text-3xl rounded-xl",
md: "px-md py-sm text-md rounded-md",
lg: "px-lg py-md text-lg rounded-lg",
xl: "px-xl py-lg text-3xl rounded-xl",
},
},
defaultVariants: {
Expand Down
2 changes: 1 addition & 1 deletion src/components/primitives/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export function Table<T extends Columns>({
export function createTable<T extends Columns>(columns: T) {
const TemplateTable = (props: Omit<TableProps<T>, "columns"> & ListProps) => (
// biome-ignore lint/suspicious/noExplicitAny: no reasons for it to have type errors
<Table {...(props as any)} columns={columns} />
<Table size="lg" {...(props as any)} columns={columns} />
);

// biome-ignore lint/suspicious/noExplicitAny: no reasons for it to have type errors
Expand Down
33 changes: 33 additions & 0 deletions src/components/primitives/Tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
/**
* @component Tabs
* @description A flexible and customizable tabs component that supports different visual styles and navigation.
*
* @features
* - Multiple visual styles (soft, base, bold, tint, hype)
* - Responsive design with Tailwind CSS
* - Built-in navigation support using Remix's Link component
* - Customizable themes
* - Accessibility features including keyboard navigation
*
* @usage
* ```tsx
* <Tabs
* tabs={[
* { label: "Tab 1", link: "/tab1", key: "1" },
* { label: "Tab 2", link: "/tab2", key: "2" }
* ]}
* look="soft"
* theme="custom"
* />
* ```
*
* @props
* - tabs: Array of tab items with label, link, and key
* - look: Visual style variant (soft, base, bold, tint, hype)
* - size: Size variant
* - theme: Custom theme override
* - className: Additional CSS classes
* - disabled: Whether the tabs are disabled
* - to: Default navigation path
*/

import { Link, useLocation } from "@remix-run/react";

import type { ReactNode } from "react";
Expand Down
89 changes: 43 additions & 46 deletions src/components/primitives/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,52 @@ import { tv } from "tailwind-variants";
import { mergeClass } from "../../utils/css";
import type { Component, Styled } from "../../utils/types";

export const textStyles = tv(
{
base: "text-main-11 font-text text-[clamp(15px,0.4167vw+0.78125rem,20px)]",
variants: {
look: {
base: "text-main-11",
soft: "text-main-11",
bold: "text-main-12",
tint: "text-accent-12",
hype: "text-accent-11",
},
size: {
xs: "text-xs",
sm: "text-sm",
md: "text-base",
lg: "text-lg",
xl: "text-xl",
display1: "font-title font-bold leading-tight italic uppercase !text-[clamp(44px,5vw+0.875rem,104px)]",
1: "font-title !text-3xl",
2: "font-title font-bold leading-none italic !text-[clamp(38px,0.667vw+2.125rem,46px)]",
3: "font-title font-bold leading-none italic !text-[clamp(26px,0.667vw+1.375rem,34px)]",
4: "font-title font-bold leading-[1.18] !text-[clamp(18px,0.667vw+0.875rem,26px)]",
5: "font-title font-bold leading-normal !text-[clamp(15px,0.25vw+0.84375rem,18px)] uppercase tracking-[1.6px] ",
6: "font-title !text-sm",
},
interactable: {
true: "cursor-pointer select-none",
false: "",
},
export const textStyles = tv({
base: "font-text text-[clamp(15px,0.4167vw+0.78125rem,20px)]",
variants: {
look: {
base: "text-main-11",
soft: "text-main-11",
bold: "text-main-12",
tint: "text-accent-12",
hype: "text-accent-11",
},
defaultVariants: {
size: "md",
look: "base",
interactable: false,
size: {
xs: "text-xs",
sm: "text-sm",
md: "text-base",
lg: "text-lg",
xl: "text-xl",
display1: "font-title font-bold leading-tight italic uppercase !text-[clamp(44px,5vw+0.875rem,104px)]",
1: "font-title !text-3xl",
2: "font-title font-bold leading-none italic !text-[clamp(38px,0.667vw+2.125rem,46px)]",
3: "font-title font-bold leading-none italic !text-[clamp(26px,0.667vw+1.375rem,34px)]",
4: "font-title font-bold leading-[1.18] !text-[clamp(18px,0.667vw+0.875rem,26px)]",
5: "font-title font-bold leading-none !text-[clamp(15px,0.25vw+0.84375rem,18px)] uppercase tracking-[0.8px] ",
6: "font-title !text-sm",
},
interactable: {
true: "cursor-pointer select-none",
false: "",
},
compoundVariants: [
{ look: "soft", interactable: true, class: "hover:text-main-12" },
{
look: "base",
interactable: true,
class: "hover:text-main-12 active:text-main-11",
},
{ look: "bold", interactable: true, class: "hover:text-main-12" },
{ look: "tint", interactable: true, class: "hover:text-main-12" },
{ look: "hype", interactable: true, class: "hover:text-main-12" },
],
},
{ twMerge: false },
);
defaultVariants: {
size: "md",
look: "base",
interactable: false,
},
compoundVariants: [
{ look: "soft", interactable: true, class: "hover:text-main-12" },
{
look: "base",
interactable: true,
class: "hover:text-main-12 active:text-main-11",
},
{ look: "bold", interactable: true, class: "hover:text-main-12" },
{ look: "tint", interactable: true, class: "hover:text-main-12" },
{ look: "hype", interactable: true, class: "hover:text-main-12" },
],
});

export type TextProps = Component<Styled<typeof textStyles> & { bold?: boolean }, HTMLParagraphElement>;

Expand Down
2 changes: 1 addition & 1 deletion src/components/primitives/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { textStyles } from "./Text";
export const titleStyles = tv(
{
extend: textStyles,
base: "text-main-12 font-title font-bold",
base: "font-title font-bold",
variants: {
look: {
base: "text-main-12",
Expand Down
Loading
Loading