Skip to content

Commit

Permalink
feat(ui): added button component (#34)
Browse files Browse the repository at this point in the history
* chore: removed useless import

* feat(frontend): added Outfit font

* feat(ui): added Button component

* feat(ui): added onLongPress and added hover/pressed styles

* chore: added route to test buttons

* refactor(ui): improved code readability and quality
  • Loading branch information
MAXOUXAX authored Jan 14, 2024
1 parent b644088 commit 0baa50f
Show file tree
Hide file tree
Showing 13 changed files with 235 additions and 2 deletions.
1 change: 0 additions & 1 deletion expo/app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Link } from "expo-router";
import { Text } from "react-native";

export default function TabOneScreen() {
Expand Down
10 changes: 9 additions & 1 deletion expo/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,15 @@ SplashScreen.preventAutoHideAsync();

export default function RootLayout() {
const [loaded, error] = useFonts({
SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
"Outfit-Thin": require("../assets/fonts/outfit/Outfit-Thin.ttf"),
"Outfit-ExtraLight": require("../assets/fonts/outfit/Outfit-ExtraLight.ttf"),
"Outfit-Light": require("../assets/fonts/outfit/Outfit-Light.ttf"),
"Outfit-Medium": require("../assets/fonts/outfit/Outfit-Medium.ttf"),
"Outfit-Regular": require("../assets/fonts/outfit/Outfit-Regular.ttf"),
"Outfit-SemiBold": require("../assets/fonts/outfit/Outfit-SemiBold.ttf"),
"Outfit-Bold": require("../assets/fonts/outfit/Outfit-Bold.ttf"),
"Outfit-ExtraBold": require("../assets/fonts/outfit/Outfit-ExtraBold.ttf"),
"Outfit-Black": require("../assets/fonts/outfit/Outfit-Black.ttf"),
...FontAwesome.font,
});

Expand Down
46 changes: 46 additions & 0 deletions expo/app/components/buttons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Text } from "react-native";
import Button from "../../components/Button";

export default function ButtonsMania() {
return (
<>
<Text>Index</Text>
<Button>Accueil</Button>
<Button type="outline">Accueil</Button>
<Button icon="home">Accueil</Button>
<Button icon="home" type="outline">
Accueil
</Button>
<Button prependIcon="home">Accueil</Button>
<Button prependIcon="home" type="outline">
Accueil
</Button>
<Button appendIcon="arrow-forward">Suivant</Button>
<Button appendIcon="arrow-forward" type="outline">
Suivant
</Button>
<Button size="small">Accueil</Button>
<Button size="small" type="outline">
Accueil
</Button>
<Button size="small" icon="home">
Accueil
</Button>
<Button size="small" icon="home" type="outline">
Accueil
</Button>
<Button size="small" prependIcon="home">
Accueil
</Button>
<Button size="small" prependIcon="home" type="outline">
Accueil
</Button>
<Button size="small" appendIcon="arrow-forward">
Suivant
</Button>
<Button size="small" appendIcon="arrow-forward" type="outline">
Suivant
</Button>
</>
);
}
Binary file added expo/assets/fonts/outfit/Outfit-Black.ttf
Binary file not shown.
Binary file added expo/assets/fonts/outfit/Outfit-Bold.ttf
Binary file not shown.
Binary file added expo/assets/fonts/outfit/Outfit-ExtraBold.ttf
Binary file not shown.
Binary file added expo/assets/fonts/outfit/Outfit-ExtraLight.ttf
Binary file not shown.
Binary file added expo/assets/fonts/outfit/Outfit-Light.ttf
Binary file not shown.
Binary file added expo/assets/fonts/outfit/Outfit-Medium.ttf
Binary file not shown.
Binary file added expo/assets/fonts/outfit/Outfit-Regular.ttf
Binary file not shown.
Binary file added expo/assets/fonts/outfit/Outfit-SemiBold.ttf
Binary file not shown.
Binary file added expo/assets/fonts/outfit/Outfit-Thin.ttf
Binary file not shown.
180 changes: 180 additions & 0 deletions expo/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import { MaterialIcons } from "@expo/vector-icons";
import { router } from "expo-router";
import {
Pressable,
PressableStateCallbackType,
StyleSheet,
} from "react-native";
import { Text } from "./Tamed";

type ButtonProps = {
children: React.ReactNode;
onPress?: () => void;
onLongPress?: () => void;
href?: string;
disabled?: boolean;
type?: "filled" | "outline";
icon?: keyof typeof MaterialIcons.glyphMap;
prependIcon?: keyof typeof MaterialIcons.glyphMap;
appendIcon?: keyof typeof MaterialIcons.glyphMap;
size?: "small" | "normal";
};

const ICON_SIZE_SMALL = 20;
const ICON_SIZE_NORMAL = 30;
const ICON_COLOR_FILLED = "white";
const ICON_COLOR_OUTLINE = "#1A1A1A";

const Button: React.FC<ButtonProps> = ({
children,
type = "filled",
size = "normal",
disabled = false,
appendIcon,
href,
icon,
onPress,
onLongPress,
prependIcon,
}) => {
const isSmall = size === "small";
const isFilled = type === "filled";
const iconSize = isSmall ? ICON_SIZE_SMALL : ICON_SIZE_NORMAL;
const iconColor = isFilled ? ICON_COLOR_FILLED : ICON_COLOR_OUTLINE;

const buttonStyles = [
styles.button,
icon && (isSmall ? styles.iconSmall : styles.iconNormal),
!icon && (isSmall ? styles.small : styles.normal),
prependIcon &&
(isSmall
? styles.smallPrependIconPadding
: styles.normalPrependIconPadding),
!prependIcon &&
!icon &&
(isSmall ? styles.smallPadding : styles.normalPadding),
appendIcon &&
(isSmall
? styles.smallAppendIconPadding
: styles.normalAppendIconPadding),
!appendIcon &&
!icon &&
(isSmall ? styles.smallPadding : styles.normalPadding),
isFilled ? styles.filled : styles.outline,
disabled && styles.disabled,
];

const pressableStyle = (state: PressableStateCallbackType) => [
buttonStyles,
state.hovered && styles.hovered,
state.pressed && styles.pressed,
];

const handlePress = href ? () => router.push(href as any) : onPress;

return (
<Pressable
style={pressableStyle}
onPress={handlePress}
onLongPress={onLongPress}
disabled={disabled}
accessibilityLabel={children as string}
>
{prependIcon && (
<MaterialIcons name={prependIcon} size={iconSize} color={iconColor} />
)}
{icon && <MaterialIcons name={icon} size={iconSize} color={iconColor} />}
{!icon && (
<Text
style={{
...styles.buttonText,
fontSize: isSmall ? 16 : 24,
color: iconColor,
fontFamily: isSmall ? "Outfit-Regular" : "Outfit-Bold",
}}
>
{children}
</Text>
)}
{appendIcon && (
<MaterialIcons name={appendIcon} size={iconSize} color={iconColor} />
)}
</Pressable>
);
};

const styles = StyleSheet.create({
button: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
alignSelf: "flex-start",
gap: 8,
borderCurve: "continuous",
},
iconSmall: {
paddingHorizontal: 8,
paddingVertical: 8,
borderRadius: 8,
},
iconNormal: {
paddingHorizontal: 16,
paddingVertical: 16,
borderRadius: 16,
},
small: {
borderRadius: 8,
},
normal: {
borderRadius: 16,
},
smallPadding: {
paddingHorizontal: 14,
paddingVertical: 5,
},
normalPadding: {
paddingHorizontal: 26,
paddingVertical: 15,
},
smallPrependIconPadding: {
paddingLeft: 8,
paddingRight: 14,
paddingVertical: 5,
},
normalPrependIconPadding: {
paddingLeft: 16,
paddingRight: 26,
paddingVertical: 15,
},
smallAppendIconPadding: {
paddingLeft: 14,
paddingRight: 8,
paddingVertical: 5,
},
normalAppendIconPadding: {
paddingLeft: 26,
paddingRight: 16,
paddingVertical: 15,
},
filled: {
backgroundColor: "#1A1A1A",
},
outline: {
borderWidth: 2,
borderColor: "#1A1A1A",
},
disabled: {
opacity: 0.5,
},
buttonText: {
textAlign: "center",
},
hovered: {
opacity: 0.8,
},
pressed: {
opacity: 0.5,
},
});

export default Button;

0 comments on commit 0baa50f

Please sign in to comment.