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