mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-10-01 14:04:51 +02:00
[eric] ui: true path-drawing icon animations (POC), sidebar-toggle divider sweeps + the plus strokes redraw on hover
This commit is contained in:
@@ -23,7 +23,8 @@ import { LayoutGrid } from 'lucide-react';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import { Settings as LucideSettings } from 'lucide-react';
|
||||
import { Palette } from 'lucide-react';
|
||||
import { PanelLeft, ArrowLeft, ArrowRight, Plus } from 'lucide-react';
|
||||
import { ArrowLeft, ArrowRight } from 'lucide-react';
|
||||
import { AnimatedPanelLeft, AnimatedPlus } from './animatedIcons';
|
||||
import RestartAltIcon from '@mui/icons-material/RestartAlt';
|
||||
import SystemUpdateAltIcon from '@mui/icons-material/SystemUpdateAlt';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
@@ -392,12 +393,10 @@ const AppShell: React.FC = () => {
|
||||
color: c.text.tertiary,
|
||||
p: 0.5,
|
||||
borderRadius: 1,
|
||||
'& svg': { transition: 'transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)' },
|
||||
'&:hover': { color: c.text.secondary, bgcolor: `${c.text.tertiary}14` },
|
||||
'&:hover svg': { transform: 'translateX(-1.5px) scale(1.08)' },
|
||||
}}
|
||||
>
|
||||
<PanelLeft size={18} />
|
||||
<AnimatedPanelLeft size={18} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Back">
|
||||
@@ -680,12 +679,10 @@ const AppShell: React.FC = () => {
|
||||
p: 0.25,
|
||||
mr: 0.25,
|
||||
borderRadius: 1,
|
||||
'& svg': { transition: 'transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)' },
|
||||
'&:hover': { color: c.accent.primary, bgcolor: `${c.accent.primary}14` },
|
||||
'&:hover svg': { transform: 'rotate(90deg)' },
|
||||
}}
|
||||
>
|
||||
<Plus size={15} />
|
||||
<AnimatedPlus size={15} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{dashboardList.length > 0 && (
|
||||
@@ -939,12 +936,10 @@ const AppShell: React.FC = () => {
|
||||
p: 0.25,
|
||||
mr: 0.25,
|
||||
borderRadius: 1,
|
||||
'& svg': { transition: 'transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)' },
|
||||
'&:hover': { color: c.accent.primary, bgcolor: `${c.accent.primary}14` },
|
||||
'&:hover svg': { transform: 'rotate(90deg)' },
|
||||
}}
|
||||
>
|
||||
<Plus size={15} />
|
||||
<AnimatedPlus size={15} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{appsList.length > 0 && (
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
// True path-drawing sidebar glyphs: the SVG strokes themselves animate on hover
|
||||
// (not just a transform), then settle. Always fully visible at rest, so a hover
|
||||
// that's interrupted mid-flight never leaves a half-drawn icon. Geometry matches
|
||||
// the lucide line-icons they replace so the static look is unchanged.
|
||||
|
||||
const SPRING = { type: 'spring', stiffness: 380, damping: 20 } as const;
|
||||
|
||||
type Props = { size?: number };
|
||||
|
||||
const svgBase = {
|
||||
fill: 'none',
|
||||
stroke: 'currentColor',
|
||||
strokeWidth: 2,
|
||||
strokeLinecap: 'round' as const,
|
||||
strokeLinejoin: 'round' as const,
|
||||
viewBox: '0 0 24 24',
|
||||
};
|
||||
|
||||
// Panel toggle: the inner divider sweeps left, like the panel collapsing.
|
||||
export function AnimatedPanelLeft({ size = 18 }: Props) {
|
||||
return (
|
||||
<motion.svg width={size} height={size} {...svgBase} initial="rest" animate="rest" whileHover="hover">
|
||||
<rect x="3" y="3" width="18" height="18" rx="2" />
|
||||
<motion.line
|
||||
x1="9" y1="3" x2="9" y2="21"
|
||||
variants={{ rest: { x: 0 }, hover: { x: -2.5 } }}
|
||||
transition={SPRING}
|
||||
/>
|
||||
</motion.svg>
|
||||
);
|
||||
}
|
||||
|
||||
// Plus: both strokes redraw from nothing, the classic "new" flourish.
|
||||
export function AnimatedPlus({ size = 16 }: Props) {
|
||||
return (
|
||||
<motion.svg width={size} height={size} {...svgBase} initial="rest" animate="rest" whileHover="hover">
|
||||
<motion.line
|
||||
x1="12" y1="5" x2="12" y2="19"
|
||||
variants={{ rest: { pathLength: 1 }, hover: { pathLength: [0, 1] } }}
|
||||
transition={{ duration: 0.34, ease: 'easeOut' }}
|
||||
/>
|
||||
<motion.line
|
||||
x1="5" y1="12" x2="19" y2="12"
|
||||
variants={{ rest: { pathLength: 1 }, hover: { pathLength: [0, 1] } }}
|
||||
transition={{ duration: 0.34, ease: 'easeOut', delay: 0.06 }}
|
||||
/>
|
||||
</motion.svg>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user