feat: type tab scroll
This commit is contained in:
parent
4a425652c6
commit
be6375f7a6
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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==}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import { domMax } from "framer-motion"
|
||||
|
||||
export default domMax
|
||||
|
|
@ -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>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue