diff --git a/web/panda.config.ts b/web/panda.config.ts
index 2b28d42de..c261cd12d 100644
--- a/web/panda.config.ts
+++ b/web/panda.config.ts
@@ -14,6 +14,7 @@ import { input } from "src/theme/components/Input/input.recipe";
import { link } from "src/theme/components/Link/link.recipe";
import { menu } from "src/theme/components/Menu/menu.recipe";
import { skeleton } from "src/theme/components/Skeleton/skeleton.recipe";
+import { tabs } from "src/theme/components/Tabs/tabs.recipe";
import { titleInput } from "src/theme/components/TitleInput/titleInput.recipe";
// TODO: Dark mode = 40%
@@ -69,6 +70,7 @@ export default defineConfig({
button: button,
link: link,
menu: menu,
+ tabs: tabs,
checkbox: checkbox,
skeleton: skeleton,
},
diff --git a/web/src/screens/profile/components/Content/Content.tsx b/web/src/screens/profile/components/Content/Content.tsx
index 74323f287..d3e233852 100644
--- a/web/src/screens/profile/components/Content/Content.tsx
+++ b/web/src/screens/profile/components/Content/Content.tsx
@@ -1,8 +1,13 @@
-import { Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react";
-
import { PublicProfile } from "src/api/openapi/schemas";
import { MixedPostList } from "src/components/feed/mixed/MixedPostList";
import { Unready } from "src/components/site/Unready";
+import {
+ Tabs,
+ TabsContent,
+ TabsIndicator,
+ TabsList,
+ TabsTrigger,
+} from "src/theme/components/Tabs";
import { CollectionList } from "../CollectionList/CollectionList";
import { PostList } from "../PostList/PostList";
@@ -18,30 +23,32 @@ export function Content(props: PublicProfile) {
return (
-
-
- Posts
- Replies
- Collections
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ Posts
+ Replies
+ Collections
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
diff --git a/web/src/theme/components/Tabs/index.ts b/web/src/theme/components/Tabs/index.ts
new file mode 100644
index 000000000..587caec3a
--- /dev/null
+++ b/web/src/theme/components/Tabs/index.ts
@@ -0,0 +1,32 @@
+import { Tabs as ArkTabs } from "@ark-ui/react/tabs";
+import { styled } from "styled-system/jsx";
+import { tabs } from "styled-system/recipes";
+
+import { createStyleContext } from "src/theme/create-style-context";
+
+const { withProvider, withContext } = createStyleContext(tabs);
+
+const Tabs = withProvider(styled(ArkTabs.Root), "root");
+const TabsContent = withContext(styled(ArkTabs.Content), "content");
+const TabsIndicator = withContext(styled(ArkTabs.Indicator), "indicator");
+const TabsList = withContext(styled(ArkTabs.List), "list");
+const TabsTrigger = withContext(styled(ArkTabs.Trigger), "trigger");
+
+const Root = Tabs;
+const Content = TabsContent;
+const Indicator = TabsIndicator;
+const List = TabsList;
+const Trigger = TabsTrigger;
+
+export {
+ Content,
+ Indicator,
+ List,
+ Root,
+ Tabs,
+ TabsContent,
+ TabsIndicator,
+ TabsList,
+ TabsTrigger,
+ Trigger,
+};
diff --git a/web/src/theme/components/Tabs/tabs.recipe.ts b/web/src/theme/components/Tabs/tabs.recipe.ts
new file mode 100644
index 000000000..349b20763
--- /dev/null
+++ b/web/src/theme/components/Tabs/tabs.recipe.ts
@@ -0,0 +1,261 @@
+import { tabsAnatomy } from "@ark-ui/react";
+import { defineSlotRecipe } from "@pandacss/dev";
+
+export const tabs = defineSlotRecipe({
+ className: "tabs",
+ slots: tabsAnatomy.keys(),
+ base: {
+ root: {
+ display: "flex",
+ width: "full",
+ _horizontal: {
+ flexDirection: "column",
+ },
+ _vertical: {
+ flexDirection: "row",
+ },
+ },
+ list: {
+ display: "flex",
+ flexShrink: "0",
+ _horizontal: {
+ flexDirection: "row",
+ },
+ _vertical: {
+ flexDirection: "column",
+ },
+ overflow: "auto",
+ position: "relative",
+ scrollbarWidth: "none",
+ "&::-webkit-scrollbar": {
+ display: "none",
+ },
+ },
+ trigger: {
+ alignItems: "center",
+ color: "fg.muted",
+ cursor: "pointer",
+ display: "inline-flex",
+ flexShrink: "0",
+ fontWeight: "semibold",
+ gap: "2",
+ justifyContent: "center",
+ transitionDuration: "normal",
+ transitionProperty: "color, background, border-color",
+ transitionTimingFunction: "default",
+ whiteSpace: "nowrap",
+ _disabled: {
+ color: "fg.disabled",
+ cursor: "not-allowed",
+ _hover: {
+ color: "fg.disabled",
+ },
+ },
+ _hover: {
+ color: "fg.muted",
+ },
+ _selected: {
+ color: "fg.default",
+ _hover: {
+ color: "fg.default",
+ },
+ },
+ _vertical: {
+ justifyContent: "start",
+ },
+ },
+ },
+ defaultVariants: {
+ size: "md",
+ },
+ variants: {
+ variant: {
+ line: {
+ list: {
+ _horizontal: {
+ boxShadow: "0 -1px 0 0 inset var(--colors-border-default)",
+ gap: "4",
+ },
+ _vertical: {
+ boxShadow: "1px 0 0 0 inset var(--colors-border-default)",
+ gap: "1",
+ },
+ },
+ indicator: {
+ background: "colorPalette.default",
+ _horizontal: {
+ height: "2px",
+ bottom: "0",
+ },
+ _vertical: {
+ width: "2px",
+ left: "0",
+ },
+ },
+ content: {
+ pt: "4",
+ },
+ trigger: {
+ _horizontal: {
+ pb: "2.5",
+ },
+ },
+ },
+ outline: {
+ list: {
+ _horizontal: {
+ mb: "-1px",
+ },
+ _vertical: {
+ mr: "-1px",
+ },
+ },
+ trigger: {
+ borderColor: "transparent",
+ borderWidth: "1px",
+ _horizontal: {
+ borderTopRadius: "l2",
+ },
+ _vertical: {
+ borderTopLeftRadius: "l2",
+ borderBottomLeftRadius: "l2",
+ },
+ _selected: {
+ background: "bg.default",
+ borderColor: "accent.500",
+ _horizontal: {
+ borderBottomColor: "transparent",
+ },
+ _vertical: {
+ borderRightColor: "transparent",
+ },
+ },
+ },
+ content: {
+ borderWidth: "1px",
+ borderColor: "accent.500",
+ background: "bg.default",
+ width: "full",
+ },
+ },
+ },
+ size: {
+ sm: {
+ trigger: {
+ "& svg": {
+ width: "4",
+ height: "4",
+ },
+ },
+ },
+ md: {
+ trigger: {
+ "& svg": {
+ width: "5",
+ height: "5",
+ },
+ },
+ },
+ lg: {
+ trigger: {
+ "& svg": {
+ width: "5",
+ height: "5",
+ },
+ },
+ },
+ },
+ },
+ compoundVariants: [
+ {
+ size: "sm",
+ variant: "outline",
+ css: {
+ trigger: {
+ h: "9",
+ minW: "9",
+ textStyle: "sm",
+ px: "3.5",
+ },
+ content: {
+ p: "3.5",
+ },
+ },
+ },
+ {
+ size: "md",
+ variant: "outline",
+ css: {
+ trigger: {
+ h: "10",
+ minW: "10",
+ textStyle: "sm",
+ px: "4",
+ },
+ content: {
+ p: "4",
+ },
+ },
+ },
+ {
+ size: "lg",
+ variant: "outline",
+ css: {
+ trigger: {
+ h: "11",
+ minW: "11",
+ textStyle: "md",
+ px: "4.5",
+ },
+ content: {
+ p: "4.5",
+ },
+ },
+ },
+ {
+ size: "sm",
+ variant: "line",
+ css: {
+ trigger: {
+ fontSize: "sm",
+ h: "9",
+ minW: "9",
+ px: "2.5",
+ },
+ content: {
+ pt: "3",
+ },
+ },
+ },
+ {
+ size: "md",
+ variant: "line",
+ css: {
+ trigger: {
+ fontSize: "md",
+ h: "10",
+ minW: "10",
+ px: "3",
+ },
+ content: {
+ pt: "4",
+ },
+ },
+ },
+ {
+ size: "lg",
+ variant: "line",
+ css: {
+ trigger: {
+ px: "3.5",
+ h: "11",
+ minW: "11",
+ fontSize: "md",
+ },
+ content: {
+ pt: "5",
+ },
+ },
+ },
+ ],
+});
diff --git a/web/styled-system/recipes/index.d.ts b/web/styled-system/recipes/index.d.ts
index dae106766..3d020d6fb 100644
--- a/web/styled-system/recipes/index.d.ts
+++ b/web/styled-system/recipes/index.d.ts
@@ -8,4 +8,5 @@ export * from './link';
export * from './menu';
export * from './checkbox';
export * from './skeleton';
-export * from './select';
\ No newline at end of file
+export * from './select';
+export * from './tabs';
\ No newline at end of file
diff --git a/web/styled-system/recipes/index.mjs b/web/styled-system/recipes/index.mjs
index 4a1e51299..d700eb0af 100644
--- a/web/styled-system/recipes/index.mjs
+++ b/web/styled-system/recipes/index.mjs
@@ -7,4 +7,5 @@ export * from './link.mjs';
export * from './menu.mjs';
export * from './checkbox.mjs';
export * from './skeleton.mjs';
-export * from './select.mjs';
\ No newline at end of file
+export * from './select.mjs';
+export * from './tabs.mjs';
\ No newline at end of file
diff --git a/web/styled-system/recipes/tabs.d.ts b/web/styled-system/recipes/tabs.d.ts
new file mode 100644
index 000000000..495063c31
--- /dev/null
+++ b/web/styled-system/recipes/tabs.d.ts
@@ -0,0 +1,29 @@
+/* eslint-disable */
+import type { ConditionalValue } from '../types/index';
+import type { Pretty } from '../types/helpers';
+import type { DistributiveOmit } from '../types/system-types';
+
+interface TabsVariant {
+ variant: "line" | "outline"
+size: "sm" | "md" | "lg"
+}
+
+type TabsVariantMap = {
+ [key in keyof TabsVariant]: Array
+}
+
+export type TabsVariantProps = {
+ [key in keyof TabsVariant]?: TabsVariant[key]
+}
+
+export interface TabsRecipe {
+ __type: TabsVariantProps
+ (props?: TabsVariantProps): Pretty>
+ raw: (props?: TabsVariantProps) => TabsVariantProps
+ variantMap: TabsVariantMap
+ variantKeys: Array
+ splitVariantProps(props: Props): [TabsVariantProps, Pretty>]
+}
+
+
+export declare const tabs: TabsRecipe
\ No newline at end of file
diff --git a/web/styled-system/recipes/tabs.mjs b/web/styled-system/recipes/tabs.mjs
new file mode 100644
index 000000000..eb90cc57f
--- /dev/null
+++ b/web/styled-system/recipes/tabs.mjs
@@ -0,0 +1,152 @@
+import { splitProps, getSlotCompoundVariant } from '../helpers.mjs';
+import { createRecipe } from './create-recipe.mjs';
+
+const tabsDefaultVariants = {
+ "size": "md"
+}
+const tabsCompoundVariants = [
+ {
+ "size": "sm",
+ "variant": "outline",
+ "css": {
+ "trigger": {
+ "h": "9",
+ "minW": "9",
+ "textStyle": "sm",
+ "px": "3.5"
+ },
+ "content": {
+ "p": "3.5"
+ }
+ }
+ },
+ {
+ "size": "md",
+ "variant": "outline",
+ "css": {
+ "trigger": {
+ "h": "10",
+ "minW": "10",
+ "textStyle": "sm",
+ "px": "4"
+ },
+ "content": {
+ "p": "4"
+ }
+ }
+ },
+ {
+ "size": "lg",
+ "variant": "outline",
+ "css": {
+ "trigger": {
+ "h": "11",
+ "minW": "11",
+ "textStyle": "md",
+ "px": "4.5"
+ },
+ "content": {
+ "p": "4.5"
+ }
+ }
+ },
+ {
+ "size": "sm",
+ "variant": "line",
+ "css": {
+ "trigger": {
+ "fontSize": "sm",
+ "h": "9",
+ "minW": "9",
+ "px": "2.5"
+ },
+ "content": {
+ "pt": "3"
+ }
+ }
+ },
+ {
+ "size": "md",
+ "variant": "line",
+ "css": {
+ "trigger": {
+ "fontSize": "md",
+ "h": "10",
+ "minW": "10",
+ "px": "3"
+ },
+ "content": {
+ "pt": "4"
+ }
+ }
+ },
+ {
+ "size": "lg",
+ "variant": "line",
+ "css": {
+ "trigger": {
+ "px": "3.5",
+ "h": "11",
+ "minW": "11",
+ "fontSize": "md"
+ },
+ "content": {
+ "pt": "5"
+ }
+ }
+ }
+]
+
+const tabsSlotNames = [
+ [
+ "root",
+ "tabs__root"
+ ],
+ [
+ "list",
+ "tabs__list"
+ ],
+ [
+ "trigger",
+ "tabs__trigger"
+ ],
+ [
+ "content",
+ "tabs__content"
+ ],
+ [
+ "indicator",
+ "tabs__indicator"
+ ]
+]
+const tabsSlotFns = /* @__PURE__ */ tabsSlotNames.map(([slotName, slotKey]) => [slotName, createRecipe(slotKey, tabsDefaultVariants, getSlotCompoundVariant(tabsCompoundVariants, slotName))])
+
+const tabsFn = (props = {}) => {
+ return Object.fromEntries(tabsSlotFns.map(([slotName, slotFn]) => [slotName, slotFn(props)]))
+}
+
+const tabsVariantKeys = [
+ "variant",
+ "size"
+]
+
+export const tabs = /* @__PURE__ */ Object.assign(tabsFn, {
+ __recipe__: false,
+ __name__: 'tabs',
+ raw: (props) => props,
+ variantKeys: tabsVariantKeys,
+ variantMap: {
+ "variant": [
+ "line",
+ "outline"
+ ],
+ "size": [
+ "sm",
+ "md",
+ "lg"
+ ]
+},
+ splitVariantProps(props) {
+ return splitProps(props, tabsVariantKeys)
+ },
+})
\ No newline at end of file