rotation border
This commit is contained in:
@@ -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 = "J’ai 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 {
|
||||||
|
|||||||
@@ -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"}
|
||||||
|
|||||||
Reference in New Issue
Block a user