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
// 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
const RotationBorder = ({ children, style, className, active = true }) => {
const classes = ["box", active ? "a" : null, className]
const RotationBorder = ({
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)
.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 (
<div className={classes} style={style}>
<div className={classes} style={inlineStyle}>
{children}
</div>
);
@@ -1,29 +1,36 @@
.box {
.rotation-border {
--border-angle: 0deg;
border-radius: 12px;
width: 100%;
height: 260px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0px 2px 4px hsl(0 0% 0% / 25%);
animation: border-angle-rotate 5s infinite linear;
border: 2px solid transparent;
--rotation-border-width: 1px;
--rotation-border-radius: 0px;
--rotation-border-duration: 5s;
--rotation-border-color-1: #f94697;
--rotation-border-color-2: #7023f7;
--rotation-border-fill: transparent;
border: var(--rotation-border-width) solid transparent;
border-radius: var(--rotation-border-radius);
box-sizing: border-box;
display: block;
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 {
background: linear-gradient(#11012f, #11012f) padding-box,
conic-gradient(
from var(--border-angle),
oklch(0.6659 0.2211 304.21),
oklch(0.6659 0.2211 304.21 / 0%),
oklch(0.6659 0.2211 304.21),
oklch(0.6659 0.2211 304.21 / 0%),
oklch(0.6659 0.2211 304.21)
)
border-box;
}
.rotation-border--active {
animation: border-angle-rotate var(--rotation-border-duration) linear infinite;
}
.rotation-border--static {
animation: none;
}
@keyframes border-angle-rotate {
+2 -2
View File
@@ -304,7 +304,7 @@ const Home = () => {
onPress={handleStageAction}
disabled={continueDisabled}
/>
<BorderGradientButton
{/* <BorderGradientButton
containerStyle={{ width: Platform.OS === "web" ? 250 : "100%" }}
title={"Test Alert"}
onPress={() =>
@@ -313,7 +313,7 @@ const Home = () => {
{ text: "OK", onPress: () => console.log("OK pressé") },
])
}
/>
/> */}
{/* <BorderGradientButton
containerStyle={{ width: Platform.OS === "web" ? 250 : "100%" }}
title={"Continuer la création"}