feat: type tab scroll

This commit is contained in:
DIYgod 2024-04-11 23:29:53 +08:00
parent 4a425652c6
commit be6375f7a6
No known key found for this signature in database
7 changed files with 125 additions and 103 deletions

View File

@ -28,6 +28,7 @@
"class-variance-authority": "0.7.0",
"clsx": "2.1.0",
"electron-updater": "^6.1.7",
"framer-motion": "11.0.27",
"react-router-dom": "6.22.3",
"tailwind-merge": "2.2.2",
"tailwindcss-animate": "1.0.7"

View File

@ -26,6 +26,9 @@ dependencies:
electron-updater:
specifier: ^6.1.7
version: 6.1.8
framer-motion:
specifier: 11.0.27
version: 11.0.27(react-dom@18.2.0)(react@18.2.0)
react-router-dom:
specifier: 6.22.3
version: 6.22.3(react-dom@18.2.0)(react@18.2.0)
@ -3394,6 +3397,25 @@ packages:
mime-types: 2.1.35
dev: true
/framer-motion@11.0.27(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-OmY1hnBXxUfvQTuoPqumAiXYPEt8jY31Fqbmihf/NR29XUL9BkRPHrqVqtJS7TLKriwRt+0pbwiO9tnziZTJzA==}
peerDependencies:
'@emotion/is-prop-valid': '*'
react: ^18.0.0
react-dom: ^18.0.0
peerDependenciesMeta:
'@emotion/is-prop-valid':
optional: true
react:
optional: true
react-dom:
optional: true
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
tslib: 2.6.2
dev: false
/fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
dev: true
@ -5300,7 +5322,6 @@ packages:
/tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
dev: true
/type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}

View File

@ -2,59 +2,96 @@ import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@renderer/components/ui/tooltip"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@renderer/components/ui/tabs"
TooltipTrigger
} from '@renderer/components/ui/tooltip'
import { m, useScroll, useMotionValueEvent } from 'framer-motion'
import { useRef, useState } from 'react'
function Content({ type }: { type: string }) {
return (
<div className="w-80">
<div>{type}</div>
</div>
)
}
export function TypeTab() {
const items = [
{
name: 'Articles',
icon: <i className="i-mingcute-news-fill" />,
className: 'text-indigo-600'
},
{
name: 'Social Media',
icon: <i className="i-mingcute-twitter-fill" />,
className: 'text-sky-600'
},
{
name: 'Pictures',
icon: <i className="i-mingcute-pic-fill" />,
className: 'text-green-600'
},
{
name: 'Videos',
icon: <i className="i-mingcute-youtube-fill" />,
className: 'text-red-600'
},
{
name: 'Audios',
icon: <i className="i-mingcute-headphone-fill" />,
className: 'text-purple-600'
},
{
name: 'Notifications',
icon: <i className="i-mingcute-notification-fill" />,
className: 'text-yellow-600'
}
]
const carouselRef = useRef<HTMLDivElement>(null)
const { scrollXProgress } = useScroll({
container: carouselRef
})
const [xProgress, setXProgress] = useState(0)
useMotionValueEvent(scrollXProgress, "change", (value) => {
setXProgress(value);
})
return (
<TooltipProvider delayDuration={300}>
<Tabs defaultValue="articles">
<TabsList className="w-full justify-around text-xl my-2">
<TabsTrigger value="articles" className="data-[state=active]:text-indigo-600">
<div className="flex text-zinc-500 w-full justify-around text-xl my-2">
{items.map((item, index) => (
<m.div
key={item.name}
className={item.className}
style={{
filter: `grayscale(${Math.min(Math.abs(xProgress - 1 / (items.length - 1) * index) * (items.length - 1), 1) * 100}%)`,
}}
onClick={() => {
if (carouselRef.current) {
carouselRef.current.scrollTo({
left: carouselRef.current.clientWidth * index,
behavior: 'smooth'
})
}
}}
>
<Tooltip>
<TooltipTrigger><i className="i-mingcute-news-fill" /></TooltipTrigger>
<TooltipContent side="bottom">Articles</TooltipContent>
<TooltipTrigger>{item.icon}</TooltipTrigger>
<TooltipContent side="bottom">{item.name}</TooltipContent>
</Tooltip>
</TabsTrigger>
<TabsTrigger value="social-media" className="data-[state=active]:text-sky-600">
<Tooltip>
<TooltipTrigger><i className="i-mingcute-twitter-fill" /></TooltipTrigger>
<TooltipContent side="bottom">Social Media</TooltipContent>
</Tooltip>
</TabsTrigger>
<TabsTrigger value="pictures" className="data-[state=active]:text-green-600">
<Tooltip>
<TooltipTrigger><i className="i-mingcute-pic-fill" /></TooltipTrigger>
<TooltipContent side="bottom">Pictures</TooltipContent>
</Tooltip>
</TabsTrigger>
<TabsTrigger value="videos" className="data-[state=active]:text-red-600">
<Tooltip>
<TooltipTrigger><i className="i-mingcute-youtube-fill" /></TooltipTrigger>
<TooltipContent side="bottom">Videos</TooltipContent>
</Tooltip>
</TabsTrigger>
<TabsTrigger value="audios" className="data-[state=active]:text-purple-600">
<Tooltip>
<TooltipTrigger><i className="i-mingcute-headphone-fill" /></TooltipTrigger>
<TooltipContent side="bottom">Audios</TooltipContent>
</Tooltip>
</TabsTrigger>
<TabsTrigger value="notifications" className="data-[state=active]:text-yellow-600">
<Tooltip>
<TooltipTrigger><i className="i-mingcute-notification-fill" /></TooltipTrigger>
<TooltipContent side="bottom">Notifications</TooltipContent>
</Tooltip>
</TabsTrigger>
</TabsList>
<TabsContent value="articles">Articles</TabsContent>
<TabsContent value="social-media">Social Media</TabsContent>
<TabsContent value="pictures">Pictures</TabsContent>
<TabsContent value="videos">Videos</TabsContent>
<TabsContent value="audios">Audios</TabsContent>
<TabsContent value="notifications">Notifications</TabsContent>
</Tabs>
</m.div>
))}
</div>
<div className="w-full h-full flex snap-x snap-mandatory overflow-x-auto" ref={carouselRef}>
{items.map((item) => (
<section key={item.name} className="snap-center shrink-0">
<Content type={item.name} />
</section>
))}
</div>
</TooltipProvider>
)
}

View File

@ -1,53 +0,0 @@
import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"
import { cn } from "@renderer/lib/utils"
const Tabs = TabsPrimitive.Root
const TabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
>(({ className, ...props }, ref) => (
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center text-muted-foreground",
className
)}
{...props}
/>
))
TabsList.displayName = TabsPrimitive.List.displayName
const TabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap data-[state=active]:text-foreground",
className
)}
{...props}
/>
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
const TabsContent = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className
)}
{...props}
/>
))
TabsContent.displayName = TabsPrimitive.Content.displayName
export { Tabs, TabsList, TabsTrigger, TabsContent }

View File

@ -0,0 +1,3 @@
import { domMax } from "framer-motion"
export default domMax

View File

@ -4,6 +4,7 @@ import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { RouterProvider, createBrowserRouter } from 'react-router-dom'
import { LazyMotion, MotionConfig } from "framer-motion"
const router = createBrowserRouter([
{
@ -22,8 +23,20 @@ const router = createBrowserRouter([
}
])
const loadFeatures = () =>
import("./framer-lazy-feature").then((res) => res.default)
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<RouterProvider router={router} />
<LazyMotion features={loadFeatures} strict key="framer">
<MotionConfig
transition={{
type: "spring",
duration: 0.3,
}}
>
<RouterProvider router={router} />
</MotionConfig>
</LazyMotion>
</React.StrictMode>
)

View File

@ -3,7 +3,7 @@ import { TypeTab } from '@renderer/components/type-tab'
export function Component() {
return (
<div className="flex h-full">
<div className="w-80 pt-10 px-3 border-r shrink-0">
<div className="w-80 pt-10 border-r shrink-0 flex flex-col">
<TypeTab />
</div>
<div className="w-80 pt-10 px-5 border-r shrink-0">Two</div>