Component
Add: - Badge - Container Voting Add: - screens/Voting Fix: - (tabs)/ index, contribution, status # No Issue
This commit is contained in:
189
components/Badge/BadgeCustom.tsx
Normal file
189
components/Badge/BadgeCustom.tsx
Normal file
@@ -0,0 +1,189 @@
|
||||
import React from "react";
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextStyle,
|
||||
View,
|
||||
ViewProps,
|
||||
ViewStyle,
|
||||
} from "react-native";
|
||||
|
||||
type BadgeVariant = "filled" | "light" | "outline" | "dot";
|
||||
type BadgeColor =
|
||||
| "primary"
|
||||
| "success"
|
||||
| "warning"
|
||||
| "danger"
|
||||
| "gray"
|
||||
| "dark";
|
||||
type BadgeSize = "xs" | "sm" | "md" | "lg";
|
||||
|
||||
interface BadgeProps extends ViewProps {
|
||||
children: React.ReactNode;
|
||||
variant?: BadgeVariant;
|
||||
color?: BadgeColor;
|
||||
size?: BadgeSize;
|
||||
leftIcon?: React.ReactNode;
|
||||
rightIcon?: React.ReactNode;
|
||||
radius?: number;
|
||||
fullWidth?: boolean;
|
||||
textColor?: string;
|
||||
}
|
||||
|
||||
const BadgeCustom: React.FC<BadgeProps> = ({
|
||||
children,
|
||||
variant = "filled",
|
||||
color = "primary",
|
||||
size = "md",
|
||||
leftIcon,
|
||||
rightIcon,
|
||||
radius = 50,
|
||||
fullWidth = false,
|
||||
textColor = "#fff",
|
||||
style,
|
||||
...props
|
||||
}) => {
|
||||
const colors = {
|
||||
primary: "#339AF0",
|
||||
success: "#40C057",
|
||||
warning: "#FAB005",
|
||||
danger: "#FA5252",
|
||||
gray: "#868E96",
|
||||
dark: "#212529",
|
||||
};
|
||||
|
||||
const themeColor = colors[color];
|
||||
|
||||
// Ganti bagian sizeStyles dan styles.container
|
||||
const sizeStyles = {
|
||||
xs: {
|
||||
fontSize: 10,
|
||||
paddingHorizontal: 6,
|
||||
paddingVertical: 2,
|
||||
height: 18, // Dinaikkan dari 16 → 18 agar teks tidak terpotong
|
||||
lineHeight: 10, // 👈 Penting: match fontSize agar kontrol vertikal lebih baik
|
||||
},
|
||||
sm: {
|
||||
fontSize: 11,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 3,
|
||||
height: 20,
|
||||
lineHeight: 11,
|
||||
},
|
||||
md: {
|
||||
fontSize: 12,
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 4,
|
||||
height: 24,
|
||||
lineHeight: 12,
|
||||
},
|
||||
lg: {
|
||||
fontSize: 14,
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 6,
|
||||
height: 30,
|
||||
lineHeight: 14,
|
||||
},
|
||||
};
|
||||
|
||||
const currentSize = sizeStyles[size];
|
||||
|
||||
let variantStyles: ViewStyle & { text: TextStyle } = {
|
||||
backgroundColor: themeColor,
|
||||
borderColor: themeColor,
|
||||
borderWidth: 1,
|
||||
borderRadius: radius,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
text: { color: textColor, fontWeight: "600" },
|
||||
};
|
||||
|
||||
switch (variant) {
|
||||
case "light":
|
||||
variantStyles.backgroundColor = `${themeColor}20`;
|
||||
variantStyles.text.color = themeColor;
|
||||
break;
|
||||
case "outline":
|
||||
variantStyles.backgroundColor = "transparent";
|
||||
variantStyles.text.color = themeColor;
|
||||
break;
|
||||
case "dot":
|
||||
variantStyles.backgroundColor = themeColor;
|
||||
variantStyles.paddingHorizontal = 0;
|
||||
variantStyles.paddingVertical = 0;
|
||||
variantStyles.height = currentSize.fontSize * 2;
|
||||
variantStyles.width = currentSize.fontSize * 2;
|
||||
variantStyles.borderRadius = currentSize.fontSize;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (variant === "dot") {
|
||||
return (
|
||||
<View
|
||||
style={[variantStyles, fullWidth && styles.fullWidth, style]}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
variantStyles,
|
||||
currentSize,
|
||||
{ borderRadius: radius },
|
||||
fullWidth && styles.fullWidth,
|
||||
style,
|
||||
]}
|
||||
{...props}
|
||||
>
|
||||
{leftIcon && <View style={styles.iconContainer}>{leftIcon}</View>}
|
||||
<Text
|
||||
style={[
|
||||
styles.text,
|
||||
variantStyles.text,
|
||||
{ fontSize: currentSize.fontSize },
|
||||
]}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
{rightIcon && <View style={styles.iconContainer}>{rightIcon}</View>}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignSelf: "flex-start",
|
||||
flexDirection: "row",
|
||||
alignItems: "center", // Vertikal center anak-anak (termasuk teks)
|
||||
justifyContent: "center", // Horizontal center
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 4,
|
||||
minWidth: 20,
|
||||
borderRadius: 6,
|
||||
// ❌ Jangan gunakan `height` fix di sini — kita override per size
|
||||
},
|
||||
text: {
|
||||
fontWeight: "600",
|
||||
textAlign: "center",
|
||||
// ❌ Hapus marginHorizontal jika mengganggu alignment
|
||||
// marginHorizontal: 2, // Opsional, bisa dihapus atau dikurangi
|
||||
includeFontPadding: false, // 👈 Ini penting untuk Android!
|
||||
padding: 0, // Bersihkan padding tambahan dari font
|
||||
},
|
||||
iconContainer: {
|
||||
marginHorizontal: 2, // Lebih kecil dari sebelumnya agar tidak ganggu ukuran kecil
|
||||
},
|
||||
fullWidth: {
|
||||
width: "100%",
|
||||
alignSelf: "stretch",
|
||||
justifyContent: "center",
|
||||
},
|
||||
});
|
||||
|
||||
export default BadgeCustom;
|
||||
44
components/Container/CircleContainer.tsx
Normal file
44
components/Container/CircleContainer.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import React from "react";
|
||||
import { StyleSheet, TextInput, View } from "react-native";
|
||||
|
||||
interface CircularInputProps {
|
||||
value: string | number;
|
||||
onChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
const CircularInput: React.FC<CircularInputProps> = ({ value, onChange }) => {
|
||||
return (
|
||||
<View style={styles.circleContainer}>
|
||||
<TextInput
|
||||
value={String(value)}
|
||||
onChangeText={onChange}
|
||||
style={styles.input}
|
||||
keyboardType="numeric"
|
||||
maxLength={2} // Batasan maksimal karakter
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
circleContainer: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: 40, // Setiap setengah dari lebar/tinggi
|
||||
borderWidth: 2,
|
||||
borderColor: MainColor.yellow, // Warna kuning
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
input: {
|
||||
color: MainColor.yellow, // Warna kuning
|
||||
fontSize: 24,
|
||||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
padding: 0,
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
});
|
||||
|
||||
export default CircularInput;
|
||||
@@ -7,6 +7,10 @@ import ButtonCenteredOnly from "./Button/ButtonCenteredOnly";
|
||||
import ButtonCustom from "./Button/ButtonCustom";
|
||||
import DotButton from "./Button/DotButton";
|
||||
import FloatingButton from "./Button/FloatingButton";
|
||||
// Badge
|
||||
import BadgeCustom from "./Badge/BadgeCustom";
|
||||
// Container
|
||||
import CircleContainer from "./Container/CircleContainer";
|
||||
// Checkbox
|
||||
import CheckboxCustom from "./Checkbox/CheckboxCustom";
|
||||
import CheckboxGroup from "./Checkbox/CheckboxGroup";
|
||||
@@ -68,6 +72,8 @@ export {
|
||||
ButtonCenteredOnly,
|
||||
ButtonCustom,
|
||||
DotButton,
|
||||
// Badge
|
||||
BadgeCustom,
|
||||
// Center
|
||||
CenterCustom,
|
||||
// Checkbox
|
||||
@@ -75,6 +81,8 @@ export {
|
||||
CheckboxGroup,
|
||||
// Clickable
|
||||
ClickableCustom,
|
||||
// Container
|
||||
CircleContainer,
|
||||
// Divider
|
||||
Divider,
|
||||
DividerCustom,
|
||||
|
||||
Reference in New Issue
Block a user