Skip to content

Commit

Permalink
refactor: tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
lerte committed Oct 17, 2024
1 parent 39cd121 commit 64bf496
Show file tree
Hide file tree
Showing 16 changed files with 233 additions and 330 deletions.
2 changes: 1 addition & 1 deletion apps/docs/content/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ title: Installation
## Install

<tabs activeTabIndex={0} language="shell" tabs='[{"label":"pnpm","icon":"pnpm","content":"pnpm add actify"},{"label":"yarn","icon":"yarn","content":"yarn add actify"},{"label":"npm","icon":"npm","content":"npm i actify"}]'>
<tabs language="shell" items='[{"label":"pnpm","icon":"pnpm","content":"pnpm add actify"},{"label":"yarn","icon":"yarn","content":"yarn add actify"},{"label":"npm","icon":"npm","content":"npm i actify"}]'>
</tabs>

## tailwind.config.js
Expand Down
4 changes: 3 additions & 1 deletion apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "docs",
"private": true,
"scripts": {
"dev": "next dev --turbo",
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
Expand Down Expand Up @@ -31,8 +31,10 @@
"@types/node": "^20.12.12",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"clsx": "^2.1.1",
"postcss": "^8.4.38",
"react-live": "^4.1.6",
"tailwind-merge": "^2.5.4",
"tailwindcss": "^3.4.3",
"typescript": "^5.4.5"
},
Expand Down
53 changes: 27 additions & 26 deletions apps/docs/src/components/DocTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
'use client'

import { TabItem, Tabs } from 'actify'

import React from 'react'
import SyntaxHighlighter from '@/components/SyntaxHighlighter'
import { Tabs } from 'actify'

interface ActifyTabsProps extends React.ComponentProps<'html'> {
tabs?: string
items?: string
language?: string
activeTabIndex?: number
}

type TypeTab = [{ label: string; icon: string; content: string }]
type TypeTab = { label: string; icon: string; content: string }

type IconProps = {
name: 'pnpm' | 'yarn' | 'npm'
Expand Down Expand Up @@ -67,35 +70,33 @@ const IconMap = {
}

const DocTabs = (props: ActifyTabsProps) => {
const { activeTabIndex, language, tabs = '' } = props
const { language, items = '' } = props

const _tabs: TypeTab = JSON.parse(tabs)
const tabs: TypeTab[] = JSON.parse(items)

return (
<Tabs
activeTabIndex={activeTabIndex}
className="not-prose rounded-lg bg-surface-variant shadow-lg"
>
<div className="flex">
<Tabs.Header className="bg-transparent">
{_tabs.map((tab) => (
<Tabs.Tab key={tab.label} value={tab.label} className="">
{IconMap[tab.icon as IconProps['name']]}
{tab.label}
</Tabs.Tab>
))}
</Tabs.Header>
</div>
<Tabs.Body className="p-2 sm:p-4 bg-surface-container">
{_tabs.map((tab) => (
<Tabs.Panel key={tab.label}>
<SyntaxHighlighter lang={`${language}` || 'jsx'}>
<div className="not-prose rounded-lg bg-surface-variant shadow-lg">
<Tabs>
{tabs.map((tab) => (
<TabItem
key={tab.label}
title={
<>
{IconMap[tab.icon as IconProps['name']]}
{tab.label}
</>
}
>
<SyntaxHighlighter
lang={`${language}` || 'jsx'}
className="rounded-t-none"
>
{tab.content}
</SyntaxHighlighter>
</Tabs.Panel>
</TabItem>
))}
</Tabs.Body>
</Tabs>
</Tabs>
</div>
)
}

Expand Down
100 changes: 53 additions & 47 deletions apps/docs/src/components/DocUsage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import { Icon, Spacer, Tabs, TooltipGroup } from 'actify'
import { Icon, Spacer, TabItem, Tabs, TooltipGroup } from 'actify'

import OpenInCodeSandbox from '@/components/OpenInCodeSandbox'
import OpenInStackblitz from '@/components/OpenInStackblitz'
Expand All @@ -20,53 +20,59 @@ const DocUsage = (props: DocUsageProps) => {
})

return (
<Tabs
activeTabIndex={0}
className="not-prose rounded-lg text-on-surface-variant bg-surface-variant shadow-lg"
>
<div className="flex">
<Tabs.Header className="bg-transparent">
<Tabs.Tab value="preview">
<Icon>visibility</Icon>
Preview
</Tabs.Tab>
<Tabs.Tab value="code">
<Icon>
<svg
fill="none"
width="24"
height="24"
strokeWidth="2"
viewBox="0 0 24 24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
xmlns="http://www.w3.org/2000/svg"
>
<path d="m18 16 4-4-4-4" />
<path d="m6 8-4 4 4 4" />
<path d="m14.5 4-5 16" />
</svg>
</Icon>
Code
</Tabs.Tab>
<Spacer />
<TooltipGroup>
<ViewSource name={component} />
<OpenInCodeSandbox title={component} code={content} />
<OpenInStackblitz title={component} code={content} />
</TooltipGroup>
</Tabs.Header>
<div className="relative not-prose rounded-lg text-on-surface-variant bg-surface-variant shadow-lg">
<Tabs>
<TabItem
key="preview"
title={
<>
<Icon>visibility</Icon>
Preview
</>
}
>
<div className="p-2 sm:p-4 bg-surface-container">
<DynamicComponent />
</div>
</TabItem>
<TabItem
key="code"
title={
<>
<Icon>
<svg
fill="none"
width="24"
height="24"
strokeWidth="2"
viewBox="0 0 24 24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
xmlns="http://www.w3.org/2000/svg"
>
<path d="m18 16 4-4-4-4" />
<path d="m6 8-4 4 4 4" />
<path d="m14.5 4-5 16" />
</svg>
</Icon>
Code
</>
}
>
<div className="p-2 sm:p-4 bg-surface-container">
<SyntaxHighlighter lang="tsx">{content}</SyntaxHighlighter>
</div>
</TabItem>
</Tabs>
<div className="absolute top-3 right-4 flex">
<TooltipGroup>
<ViewSource name={component} />
<OpenInCodeSandbox title={component} code={content} />
<OpenInStackblitz title={component} code={content} />
</TooltipGroup>
</div>
<Tabs.Body className="p-2 sm:p-4 bg-surface-container">
<Tabs.Panel>
<DynamicComponent />
</Tabs.Panel>
<Tabs.Panel>
<SyntaxHighlighter lang="tsx">{content}</SyntaxHighlighter>
</Tabs.Panel>
</Tabs.Body>
</Tabs>
</div>
)
}
export default DocUsage
9 changes: 7 additions & 2 deletions apps/docs/src/components/SyntaxHighlighter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { Icon, IconButton } from 'actify'
import React, { useState } from 'react'

import { cn } from '@/utils/cn'
import { fira_code } from '@/app/fonts'
import { useMounted } from '@/hooks/useMounted'
import { useTheme } from 'next-themes'
Expand All @@ -14,7 +15,7 @@ const SyntaxHighlighter = (props: React.ComponentProps<'div'>) => {
const mounted = useMounted()
const { theme, systemTheme } = useTheme()

const { lang, children } = props
const { lang, children, className } = props
const [code, setCode] = useState('')
const [iconName, setIconName] = useState('content_copy')

Expand Down Expand Up @@ -63,7 +64,11 @@ const SyntaxHighlighter = (props: React.ComponentProps<'div'>) => {

return (
<div
className={`${fira_code.variable} group relative rounded-lg shadow-lg overflow-hidden`}
className={cn(
fira_code.variable,
['group', 'relative', 'rounded-lg', 'shadow-lg', 'overflow-hidden'],
className
)}
>
<div className="absolute top-3 right-6 cursor-pointer opacity-0 transition-opacity group-hover:opacity-100">
<IconButton variant="filled" onClick={copyCode} color="secondary">
Expand Down
47 changes: 7 additions & 40 deletions apps/docs/src/usages/tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,13 @@
import { Tabs } from 'actify'
'use client'

export default () => {
const data = [
{
label: 'HTML',
value: 'html',
content: 'HTML content'
},
{
label: 'React',
value: 'react',
content: 'React content'
},
{
label: 'Vue',
value: 'vue',
content: 'Vue content'
},
{
label: 'Angular',
value: 'angular',
content: 'Angular content'
},
{
label: 'Svelte',
value: 'svelte',
content: 'Svelte content'
}
]
import { TabItem, Tabs } from 'actify'

export default () => {
return (
<Tabs activeTabIndex={0}>
<Tabs.Header>
{data.map(({ label, value }) => (
<Tabs.Tab key={value}>{label}</Tabs.Tab>
))}
</Tabs.Header>
<Tabs.Body>
{data.map(({ value, content }) => (
<Tabs.Panel key={value}>{content}</Tabs.Panel>
))}
</Tabs.Body>
<Tabs>
<TabItem title="Recent">Recent</TabItem>
<TabItem title="Favorites">Favorites</TabItem>
<TabItem title="All">All</TabItem>
</Tabs>
)
}
6 changes: 6 additions & 0 deletions apps/docs/src/utils/cn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
79 changes: 17 additions & 62 deletions packages/actify/src/components/Tabs/Tab.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,24 @@
'use client'
import { mergeProps, useFocusRing, useTab } from 'react-aria'

import { Button } from './../Button'
import { FocusRing } from './../FocusRing'
import React from 'react'
import { motion } from 'framer-motion'
import { tv } from 'tailwind-variants'
import { useTabs } from './TabsContext'
import { Ripple } from './../Ripple'
import styles from './tabs.module.css'

const root = tv({
base: [
'h-10',
'flex',
'gap-0',
'isolate',
'sm:gap-2',
'relative',
'text-base',
'select-none',
'font-medium',
'items-center',
'justify-center',
'cursor-pointer',
'leading-relaxed'
]
})

export interface TabProps extends React.ComponentProps<'li'> {
index?: number
}

const Tab = (props: TabProps) => {
const { index, className, children, ...rest } = props

const { layoutId, activeTabIndex, scrollToTab } = useTabs()

const handleClick = (index: number) => {
scrollToTab?.(index)
}
export function Tab({ item, state }: any) {
const ref = React.useRef(null)
const { tabProps } = useTab(item, state, ref)
const { focusProps, isFocusVisible } = useFocusRing()

return (
<li role="tab" {...rest} className={root({ className })}>
<Button
onPress={() => handleClick(index!)}
variant="text"
style={
{
'--_container-shape-start-start': 0,
'--_container-shape-start-end': 0,
'--_container-shape-end-start': 0,
'--_container-shape-end-end': 0
} as React.CSSProperties
}
>
{children}
</Button>
{activeTabIndex == index && (
<motion.div
layoutId={layoutId}
// @ts-ignore
className="absolute -z-10 w-full bottom-0"
>
<div className="h-0.5 rounded-lg w-full bg-primary"></div>
</motion.div>
)}
</li>
<div
ref={ref}
className={styles['tab-item']}
{...mergeProps(tabProps, focusProps)}
>
{item.rendered}
<Ripple />
{isFocusVisible && <FocusRing />}
</div>
)
}

export { Tab }
Loading

0 comments on commit 64bf496

Please sign in to comment.