rotation border

This commit is contained in:
2025-10-06 16:08:19 +02:00
parent 042b3d9019
commit bf0184d16c
4 changed files with 151 additions and 29 deletions
@@ -0,0 +1,76 @@
import { BlurView } from "expo-blur";
import React from "react";
import { Image, Pressable, Text, View } from "react-native";
import { Palette, Style } from "../styles";
import { FONT_FAMILY } from "../styles/Fonts";
import { size } from "../styles/Style";
import RotationBorder from "./RotationBorder/RotationBorder";
const BorderGradientButton = ({
title = "Jai déjà mes paroles",
onPress,
icon,
titleStyle,
containerStyle = {},
tint = "dark",
disabled = false,
maxWidth = null,
}) => {
const pressableStyle = {
...(maxWidth ? { maxWidth } : {}),
...containerStyle,
opacity: disabled ? 0.6 : 1,
};
return (
<Pressable onPress={onPress} disabled={disabled} style={pressableStyle}>
<RotationBorder
borderWidth={2}
borderRadius={14}
colors={["#F94697", "#7023F7"]}
style={{
height: 50,
width: "100%",
zIndex: 1,
}}
>
<View
style={{
borderRadius: 14,
overflow: "hidden",
backgroundColor: "#000000b8",
width: "100%",
height: "100%",
}}
>
<BlurView
intensity={40}
tint={tint}
style={{
width: "100%",
height: "100%",
...Style.containerCenter,
...Style.containerRow,
borderRadius: 14,
gap: 11,
}}
>
{icon && <Image source={icon} style={size({ size: 16 })} />}
<Text
style={{
fontSize: 15,
color: Palette.white,
fontFamily: FONT_FAMILY.InterMedium,
...titleStyle,
}}
>
{title}
</Text>
</BlurView>
</View>
</RotationBorder>
</Pressable>
);
};
export default BorderGradientButton;
@@ -4,14 +4,53 @@ import "./rotationTestStyle.css";
// Web-only rotating gradient border container // Web-only rotating gradient border container
// Props: // Props:
// - active: show rotating gradient when true (default) // - active: animate rotation (default true)
// - colors: [primary, secondary] gradient colors
// - duration: animation duration in seconds
// - borderWidth: width of the gradient border (px)
// - borderRadius: optional corner radius (px)
// - fillColor: background color applied inside the border
// - style, className: optional DOM styles/classes // - style, className: optional DOM styles/classes
const RotationBorder = ({ children, style, className, active = true }) => { const RotationBorder = ({
const classes = ["box", active ? "a" : null, className] children,
style,
className,
active = true,
colors = ["#F94697", "#7023F7"],
duration = 5,
borderWidth = 1,
borderRadius,
fillColor = "transparent",
}) => {
const classes = [
"rotation-border",
active ? "rotation-border--active" : "rotation-border--static",
className,
]
.filter(Boolean) .filter(Boolean)
.join(" "); .join(" ");
const inlineStyle = { ...style };
inlineStyle["--rotation-border-width"] = `${borderWidth}px`;
inlineStyle["--rotation-border-color-1"] = colors[0];
inlineStyle["--rotation-border-color-2"] = colors[1] ?? colors[0];
inlineStyle["--rotation-border-duration"] = `${duration}s`;
inlineStyle["--rotation-border-fill"] = fillColor;
if (typeof borderRadius !== "undefined") {
inlineStyle.borderRadius = borderRadius;
}
if (typeof inlineStyle.borderRadius !== "undefined") {
inlineStyle["--rotation-border-radius"] =
typeof inlineStyle.borderRadius === "number"
? `${inlineStyle.borderRadius}px`
: inlineStyle.borderRadius;
}
return ( return (
<div className={classes} style={style}> <div className={classes} style={inlineStyle}>
{children} {children}
</div> </div>
); );
@@ -1,29 +1,36 @@
.box { .rotation-border {
--border-angle: 0deg; --border-angle: 0deg;
border-radius: 12px; --rotation-border-width: 1px;
width: 100%; --rotation-border-radius: 0px;
height: 260px; --rotation-border-duration: 5s;
display: flex; --rotation-border-color-1: #f94697;
justify-content: center; --rotation-border-color-2: #7023f7;
align-items: center; --rotation-border-fill: transparent;
box-shadow: 0px 2px 4px hsl(0 0% 0% / 25%); border: var(--rotation-border-width) solid transparent;
animation: border-angle-rotate 5s infinite linear; border-radius: var(--rotation-border-radius);
border: 2px solid transparent; box-sizing: border-box;
display: block;
position: relative; position: relative;
background: linear-gradient(
var(--rotation-border-fill),
var(--rotation-border-fill)
)
padding-box,
conic-gradient(
from var(--border-angle),
var(--rotation-border-color-1),
var(--rotation-border-color-2),
var(--rotation-border-color-1)
)
border-box;
}
&.a { .rotation-border--active {
background: linear-gradient(#11012f, #11012f) padding-box, animation: border-angle-rotate var(--rotation-border-duration) linear infinite;
conic-gradient( }
from var(--border-angle),
oklch(0.6659 0.2211 304.21), .rotation-border--static {
oklch(0.6659 0.2211 304.21 / 0%), animation: none;
oklch(0.6659 0.2211 304.21),
oklch(0.6659 0.2211 304.21 / 0%),
oklch(0.6659 0.2211 304.21)
)
border-box;
}
} }
@keyframes border-angle-rotate { @keyframes border-angle-rotate {
+2 -2
View File
@@ -304,7 +304,7 @@ const Home = () => {
onPress={handleStageAction} onPress={handleStageAction}
disabled={continueDisabled} disabled={continueDisabled}
/> />
<BorderGradientButton {/* <BorderGradientButton
containerStyle={{ width: Platform.OS === "web" ? 250 : "100%" }} containerStyle={{ width: Platform.OS === "web" ? 250 : "100%" }}
title={"Test Alert"} title={"Test Alert"}
onPress={() => onPress={() =>
@@ -313,7 +313,7 @@ const Home = () => {
{ text: "OK", onPress: () => console.log("OK pressé") }, { text: "OK", onPress: () => console.log("OK pressé") },
]) ])
} }
/> /> */}
{/* <BorderGradientButton {/* <BorderGradientButton
containerStyle={{ width: Platform.OS === "web" ? 250 : "100%" }} containerStyle={{ width: Platform.OS === "web" ? 250 : "100%" }}
title={"Continuer la création"} title={"Continuer la création"}