Compare commits

..

2 Commits

Author SHA1 Message Date
IluaAir
4a33b8defa add api sources 2025-10-06 00:41:57 +03:00
IluaAir
7978b1042d ripple button 2025-10-05 00:16:20 +03:00
2 changed files with 70 additions and 49 deletions

View File

@@ -0,0 +1,37 @@
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000';
const API_V1_PREFIX = '/api/v1';
const API_SOURCES = {
AUTH: `${API_BASE_URL}${API_V1_PREFIX}/auth`,
USERS: `${API_BASE_URL}${API_V1_PREFIX}/users`,
TASKS: `${API_BASE_URL}${API_V1_PREFIX}/tasks`,
}
const API_ENDPOINTS = {
AUTH: {
LOGIN: `${API_SOURCES.AUTH}/login`,
REFRESH: `${API_SOURCES.AUTH}/refresh`,
LOGOUT: `${API_SOURCES.AUTH}/logout`,
ME: `${API_SOURCES.AUTH}/me`,
REGISTER: `${API_SOURCES.AUTH}/signup`,
},
USERS: {
LIST: API_SOURCES.USERS,
BY_ID: (id) => `${API_SOURCES.USERS}/${id}`,
TASKS: (id) => `${API_SOURCES.USERS}/${id}/tasks`,
UPDATE: (id) => `${API_SOURCES.USERS}/${id}`,
DELETE: (id) => `${API_SOURCES.USERS}/${id}`,
},
TASKS: {
BY_ID: (id) => `${API_SOURCES.TASKS}/${id}`,
CREATE: `${API_SOURCES.TASKS}`,
UPDATE: (id) => `${API_SOURCES.TASKS}/${id}`,
DELETE: (id) => `${API_SOURCES.TASKS}/${id}`,
},
};
export { API_BASE_URL, API_SOURCES, API_ENDPOINTS };

View File

@@ -1,58 +1,42 @@
"use client" "use client"
import { AnimatePresence, motion } from "motion/react"
import { useState } from "react" import { useState } from "react"
import { motion, AnimatePresence } from "motion/react"
export default function ExitAnimation() { export function useRipple() {
const [isVisible, setIsVisible] = useState(true) const [ripples, setRipples] = useState([])
const container = { const addRipple = (e) => {
display: "flex", const rect = e.currentTarget.getBoundingClientRect()
flexDirection: "column", const x = e.clientX - rect.left
width: 100, const y = e.clientY - rect.top
height: 160, const id = Date.now()
position: "relative",
setRipples((prev) => [...prev, { x, y, id }])
setTimeout(() => {
setRipples((prev) => prev.filter((r) => r.id !== id))
}, 600)
} }
const box = { const Ripples = (
width: 100, <AnimatePresence>
height: 100, {ripples.map((ripple) => (
backgroundColor: "#0cdcf7", <motion.span
borderRadius: 10, key={ripple.id}
} initial={{ scale: 0, opacity: 0.6 }}
animate={{ scale: 4, opacity: 0 }}
const button = { exit={{ opacity: 0 }}
backgroundColor: "#0cdcf7", transition={{ duration: 0.6, ease: "easeOut" }}
borderRadius: 10, style={{
padding: "10px 20px", left: ripple.x,
color: "#0f1115", top: ripple.y,
position: "absolute", }}
bottom: 0, className="absolute h-8 w-8 rounded-full bg-white/70 pointer-events-none -translate-x-1/2 -translate-y-1/2"
left: 0,
right: 0,
}
return (
<div style={container}>
<AnimatePresence initial={false}>
{isVisible && (
<motion.div
initial={{ opacity: 0, scale: 0 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0 }}
style={box}
key="box"
/> />
)} ))}
</AnimatePresence> </AnimatePresence>
<motion.button
style={button}
onClick={() => setIsVisible(!isVisible)}
whileTap={{ scale: 0.95 }}
>
{isVisible ? "Hide" : "Show"}
</motion.button>
</div>
) )
return { addRipple, Ripples }
} }