diff --git a/app.json b/app.json index 3f3eb56..6b0b814 100644 --- a/app.json +++ b/app.json @@ -21,7 +21,6 @@ "package": "com.anonymous.bahla" }, "web": { - "bundler": "metro", "output": "static", "favicon": "./assets/images/favicon.png" }, diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index f3c649b..0000000 --- a/babel.config.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = function (api) { - api.cache(true); - return { - presets: [ - ["babel-preset-expo", { jsxImportSource: "nativewind" }], - "nativewind/babel", - ], - }; -}; diff --git a/metro.config.js b/metro.config.js deleted file mode 100644 index 9800736..0000000 --- a/metro.config.js +++ /dev/null @@ -1,8 +0,0 @@ -// Learn more https://docs.expo.io/guides/customizing-metro -const { getDefaultConfig } = require('expo/metro-config'); -const { withNativeWind } = require('nativewind/metro'); - -/** @type {import('expo/metro-config').MetroConfig} */ -const config = getDefaultConfig(__dirname); - -module.exports = withNativeWind(config, { input: './src/global.css' }) diff --git a/nativewind-env.d.ts b/nativewind-env.d.ts deleted file mode 100644 index fbca8c7..0000000 --- a/nativewind-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// \ No newline at end of file diff --git a/output.css b/output.css deleted file mode 100644 index a5b53bf..0000000 --- a/output.css +++ /dev/null @@ -1,608 +0,0 @@ -*, ::before, ::after { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; -} - -/* -! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com -*/ - -/* -1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) -2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) -*/ - -*, -::before, -::after { - box-sizing: border-box; - /* 1 */ - border-width: 0; - /* 2 */ - border-style: solid; - /* 2 */ - border-color: #e5e7eb; - /* 2 */ -} - -::before, -::after { - --tw-content: ''; -} - -/* -1. Use a consistent sensible line-height in all browsers. -2. Prevent adjustments of font size after orientation changes in iOS. -3. Use a more readable tab size. -4. Use the user's configured `sans` font-family by default. -5. Use the user's configured `sans` font-feature-settings by default. -6. Use the user's configured `sans` font-variation-settings by default. -7. Disable tap highlights on iOS -*/ - -html, -:host { - line-height: 1.5; - /* 1 */ - -webkit-text-size-adjust: 100%; - /* 2 */ - -moz-tab-size: 4; - /* 3 */ - -o-tab-size: 4; - tab-size: 4; - /* 3 */ - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - /* 4 */ - font-feature-settings: normal; - /* 5 */ - font-variation-settings: normal; - /* 6 */ - -webkit-tap-highlight-color: transparent; - /* 7 */ -} - -/* -1. Remove the margin in all browsers. -2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. -*/ - -body { - margin: 0; - /* 1 */ - line-height: inherit; - /* 2 */ -} - -/* -1. Add the correct height in Firefox. -2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) -3. Ensure horizontal rules are visible by default. -*/ - -hr { - height: 0; - /* 1 */ - color: inherit; - /* 2 */ - border-top-width: 1px; - /* 3 */ -} - -/* -Add the correct text decoration in Chrome, Edge, and Safari. -*/ - -abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; -} - -/* -Remove the default font size and weight for headings. -*/ - -h1, -h2, -h3, -h4, -h5, -h6 { - font-size: inherit; - font-weight: inherit; -} - -/* -Reset links to optimize for opt-in styling instead of opt-out. -*/ - -a { - color: inherit; - text-decoration: inherit; -} - -/* -Add the correct font weight in Edge and Safari. -*/ - -b, -strong { - font-weight: bolder; -} - -/* -1. Use the user's configured `mono` font-family by default. -2. Use the user's configured `mono` font-feature-settings by default. -3. Use the user's configured `mono` font-variation-settings by default. -4. Correct the odd `em` font sizing in all browsers. -*/ - -code, -kbd, -samp, -pre { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - /* 1 */ - font-feature-settings: normal; - /* 2 */ - font-variation-settings: normal; - /* 3 */ - font-size: 1em; - /* 4 */ -} - -/* -Add the correct font size in all browsers. -*/ - -small { - font-size: 80%; -} - -/* -Prevent `sub` and `sup` elements from affecting the line height in all browsers. -*/ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* -1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) -2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) -3. Remove gaps between table borders by default. -*/ - -table { - text-indent: 0; - /* 1 */ - border-color: inherit; - /* 2 */ - border-collapse: collapse; - /* 3 */ -} - -/* -1. Change the font styles in all browsers. -2. Remove the margin in Firefox and Safari. -3. Remove default padding in all browsers. -*/ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; - /* 1 */ - font-feature-settings: inherit; - /* 1 */ - font-variation-settings: inherit; - /* 1 */ - font-size: 100%; - /* 1 */ - font-weight: inherit; - /* 1 */ - line-height: inherit; - /* 1 */ - letter-spacing: inherit; - /* 1 */ - color: inherit; - /* 1 */ - margin: 0; - /* 2 */ - padding: 0; - /* 3 */ -} - -/* -Remove the inheritance of text transform in Edge and Firefox. -*/ - -button, -select { - text-transform: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Remove default button styles. -*/ - -button, -input:where([type='button']), -input:where([type='reset']), -input:where([type='submit']) { - -webkit-appearance: button; - /* 1 */ - background-color: transparent; - /* 2 */ - background-image: none; - /* 2 */ -} - -/* -Use the modern Firefox focus style for all focusable elements. -*/ - -:-moz-focusring { - outline: auto; -} - -/* -Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) -*/ - -:-moz-ui-invalid { - box-shadow: none; -} - -/* -Add the correct vertical alignment in Chrome and Firefox. -*/ - -progress { - vertical-align: baseline; -} - -/* -Correct the cursor style of increment and decrement buttons in Safari. -*/ - -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} - -/* -1. Correct the odd appearance in Chrome and Safari. -2. Correct the outline style in Safari. -*/ - -[type='search'] { - -webkit-appearance: textfield; - /* 1 */ - outline-offset: -2px; - /* 2 */ -} - -/* -Remove the inner padding in Chrome and Safari on macOS. -*/ - -::-webkit-search-decoration { - -webkit-appearance: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Change font properties to `inherit` in Safari. -*/ - -::-webkit-file-upload-button { - -webkit-appearance: button; - /* 1 */ - font: inherit; - /* 2 */ -} - -/* -Add the correct display in Chrome and Safari. -*/ - -summary { - display: list-item; -} - -/* -Removes the default spacing and border for appropriate elements. -*/ - -blockquote, -dl, -dd, -h1, -h2, -h3, -h4, -h5, -h6, -hr, -figure, -p, -pre { - margin: 0; -} - -fieldset { - margin: 0; - padding: 0; -} - -legend { - padding: 0; -} - -ol, -ul, -menu { - list-style: none; - margin: 0; - padding: 0; -} - -/* -Reset default styling for dialogs. -*/ - -dialog { - padding: 0; -} - -/* -Prevent resizing textareas horizontally by default. -*/ - -textarea { - resize: vertical; -} - -/* -1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) -2. Set the default placeholder color to the user's configured gray 400 color. -*/ - -input::-moz-placeholder, textarea::-moz-placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -input::placeholder, -textarea::placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -/* -Set the default cursor for buttons. -*/ - -button, -[role="button"] { - cursor: pointer; -} - -/* -Make sure disabled buttons don't get the pointer cursor. -*/ - -:disabled { - cursor: default; -} - -/* -1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) -2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) - This can trigger a poorly considered lint error in some tools but is included by design. -*/ - -img, -svg, -video, -canvas, -audio, -iframe, -embed, -object { - display: block; - /* 1 */ - vertical-align: middle; - /* 2 */ -} - -/* -Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) -*/ - -img, -video { - max-width: 100%; - height: auto; -} - -/* Make elements with the HTML hidden attribute stay hidden by default */ - -[hidden]:where(:not([hidden="until-found"])) { - display: none; -} - -:root { - --css-interop-darkMode: media; - --css-interop: true; - --css-interop-nativewind: true; -} - -.container { - width: 100%; -} - -@media (min-width: 640px) { - .container { - max-width: 640px; - } -} - -@media (min-width: 768px) { - .container { - max-width: 768px; - } -} - -@media (min-width: 1024px) { - .container { - max-width: 1024px; - } -} - -@media (min-width: 1280px) { - .container { - max-width: 1280px; - } -} - -@media (min-width: 1536px) { - .container { - max-width: 1536px; - } -} - -.flex { - display: flex; -} - -.bg-blue-500 { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity, 1)); -} - -.font-bold { - font-weight: 700; -} \ No newline at end of file diff --git a/package.json b/package.json index 9fceb80..e8866bf 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "@react-navigation/bottom-tabs": "^7.18.18", "@tanstack/react-query": "^5.102.8", "axios": "^1.20.0", - "babel-preset-expo": "^57.0.9", "expo": "~56.0.5", "expo-blur": "~56.0.4", "expo-constants": "~56.0.16", @@ -31,8 +30,6 @@ "expo-web-browser": "~56.0.5", "lucide-react": "^1.38.0", "lucide-react-native": "^1.38.0", - "nativewind": "^4.2.6", - "prettier-plugin-tailwindcss": "^0.5.14", "react": "19.2.3", "react-dom": "19.2.3", "react-native": "0.85.3", @@ -43,7 +40,6 @@ "react-native-svg": "15.15.4", "react-native-web": "~0.21.0", "react-native-worklets": "0.8.3", - "tailwindcss": "^3.4.19", "zod": "^4.5.4", "zustand": "^5.0.15" }, diff --git a/src/app/(tabs)/my-events.tsx b/src/app/(tabs)/my-events.tsx index 0574acc..4084b00 100644 --- a/src/app/(tabs)/my-events.tsx +++ b/src/app/(tabs)/my-events.tsx @@ -1,15 +1,22 @@ import { StyleSheet, Text, View } from 'react-native'; +import { Header } from '@/components/ui/Header'; +import { Screen } from '@/components/ui/Screen'; + import { colors } from '@/theme/colors'; import { spacing } from '@/theme/spacing'; import { typography } from '@/theme/typography'; export default function MyEventsTabScreen() { return ( - - My Events - Base ecran mes events - + +
+ + + My Events + Base ecran mes events + + ); } diff --git a/src/app/index-old.tsx b/src/app/index-old.tsx index abe6a73..ac3aad7 100644 --- a/src/app/index-old.tsx +++ b/src/app/index-old.tsx @@ -10,8 +10,6 @@ import { colors } from '@/theme/colors'; import { spacing } from '@/theme/spacing'; import { typography } from '@/theme/typography'; -import '../global.css'; - export default function Index() { const [selectedThemes, setSelectedThemes] = useState(['Soirée', 'Techno', 'Festival']); diff --git a/src/components/navigation/BahlaTabBar copy.tsx b/src/components/navigation/BahlaTabBar copy.tsx new file mode 100644 index 0000000..81971d5 --- /dev/null +++ b/src/components/navigation/BahlaTabBar copy.tsx @@ -0,0 +1,278 @@ +/* ------------------------------------------------------------------ * + * BahlaTabBar — barre d'onglets floutée, partagée par (tabs) et (org). + * + * Une seule implémentation pour les deux parcours : le verre dépoli, + * le calcul de safe area, le rendu des items et l'accessibilité sont + * identiques. Seul le bouton central change, et il est optionnel. + * + * Usage : + * }> // utilisateur + * }> + * + * Dépendances : expo-blur · expo-linear-gradient · + * react-native-safe-area-context · react-native-svg + * ------------------------------------------------------------------ */ +import { BlurView } from 'expo-blur'; +import { LinearGradient } from 'expo-linear-gradient'; +import { Tabs } from 'expo-router'; +import { useCallback, type ComponentProps } from 'react'; +import { + Platform, + Pressable, + StyleSheet, + Text, + View, + type ViewStyle, +} from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; + +import { colors, gradientDirection, gradients } from '@/theme/colors'; +import { fontFamily, typography } from '@/theme/typography'; +import { Plus } from 'lucide-react-native'; + +/** Hauteur de la barre hors safe area. La hauteur réelle y ajoute l'inset bas. */ +export const TAB_BAR_BASE_HEIGHT = 52; +const FAB_SIZE = 62; + +/** + * expo-blur ne rend rien d'exploitable sous Android 9 : sans ce repli on + * obtient un rectangle transparent et des libellés illisibles. + */ +const SUPPORTS_BLUR = Platform.OS === 'ios' || Number(Platform.Version) >= 28; + +type ExpoRouterTabBarProps = Parameters< + NonNullable['tabBar']> +>[0]; + +type Props = ExpoRouterTabBarProps & { + /** + * Nom de la route factice qui occupe l'emplacement central. + * Absent côté utilisateur — il n'y a pas de bouton flottant. + */ + fabRouteName?: string; + /** Appelé à la place d'une navigation quand on presse le bouton central. */ + onFabPress?: () => void; + /** Libellé lu par les lecteurs d'écran sur le bouton central. */ + fabAccessibilityLabel?: string; +}; + +export function BahlaTabBar({ + state, + descriptors, + navigation, + fabRouteName, + onFabPress, + fabAccessibilityLabel = 'Créer', +}: Props) { + const insets = useSafeAreaInsets(); + + const handlePress = useCallback( + (routeKey: string, routeName: string, isFocused: boolean) => { + const event = navigation.emit({ + type: 'tabPress', + target: routeKey, + canPreventDefault: true, + }); + if (isFocused || event.defaultPrevented) return; + navigation.navigate(routeName as never); + }, + [navigation], + ); + + const handleLongPress = useCallback( + (routeKey: string) => { + navigation.emit({ type: 'tabLongPress', target: routeKey }); + }, + [navigation], + ); + + return ( + + {state.routes.map((route: (typeof state.routes)[number], index: number) => { + const { options } = descriptors[route.key]; + const isFocused = state.index === index; + const tint = isFocused ? colors.primary : colors.textSecondary; + + /* --- Emplacement central : bouton flottant, pas un onglet ---- */ + if (fabRouteName && route.name === fabRouteName) { + return ( + + [ + styles.fab, + pressed && styles.fabPressed, + ]} + > + + + + + + ); + } + + /* --- Onglet ordinaire ---------------------------------------- */ + const label = + typeof options.tabBarLabel === 'string' + ? options.tabBarLabel + : (options.title ?? route.name); + + return ( + handlePress(route.key, route.name, isFocused)} + onLongPress={() => handleLongPress(route.key)} + style={styles.item} + > + + {options.tabBarIcon?.({ + focused: isFocused, + color: tint, + size: 23, + })} + {options.tabBarBadge != null && ( + + + {options.tabBarBadge} + + + )} + + + {label} + + + ); + })} + + ); +} + +const styles = StyleSheet.create({ + bar: { + position: 'absolute', + left: 0, + right: 0, + bottom: 0, + flexDirection: 'row', + alignItems: 'flex-start', + paddingTop: 8, + borderTopWidth: StyleSheet.hairlineWidth * 2, + borderTopColor: colors.border, + overflow: 'visible', + } as ViewStyle, + + item: { + flex: 1, + alignItems: 'center', + gap: 5, + // La zone tactile couvre toute la hauteur de la barre. + alignSelf: 'stretch', + paddingTop: 2, + }, + + label: { + ...typography.tabLabel, + fontFamily: undefined, // remplacé plus haut selon l'état + }, + + badge: { + position: 'absolute', + top: -4, + right: -8, + minWidth: 16, + height: 16, + paddingHorizontal: 4, + borderRadius: 999, + backgroundColor: colors.primary, + alignItems: 'center', + justifyContent: 'center', + }, + + badgeText: { + ...typography.overlineSm, + fontSize: 9, + lineHeight: 16, + letterSpacing: 0, + color: colors.onPrimary, + }, + + /* Le créneau central est plus étroit que les onglets : 84 px fixes, + comme la colonne du même nom dans la maquette. */ + fabSlot: { + width: 84, + alignItems: 'center', + }, + + fab: { + width: FAB_SIZE, + height: FAB_SIZE, + aspectRatio: 1, + borderRadius: 15, + // Remonte au-dessus de la barre et découpe un anneau dans le fond. + marginTop: -30, + overflow: 'hidden', + alignSelf: 'center', + borderWidth: 3, + borderColor: colors.deepBackground, + shadowColor: colors.primary, + shadowOffset: { width: 0, height: 14 }, + shadowOpacity: 0.85, + shadowRadius: 17, + elevation: 12, + }, + + fabPressed: { + transform: [{ scale: 0.94 }], + shadowOpacity: 0.5, + }, + + fabGradient: { + width: '100%', + height: '100%', + aspectRatio: 1, + borderRadius: 15, + alignItems: 'center', + justifyContent: 'center', + }, +}); + +export default BahlaTabBar; diff --git a/src/components/navigation/BahlaTabBar.tsx b/src/components/navigation/BahlaTabBar.tsx index 2ab060b..b95a093 100644 --- a/src/components/navigation/BahlaTabBar.tsx +++ b/src/components/navigation/BahlaTabBar.tsx @@ -13,17 +13,15 @@ * Dépendances : expo-blur · expo-linear-gradient · * react-native-safe-area-context · react-native-svg * ------------------------------------------------------------------ */ -import { BlurView } from 'expo-blur'; import { LinearGradient } from 'expo-linear-gradient'; import { Tabs } from 'expo-router'; import { useCallback, type ComponentProps } from 'react'; import { - Platform, Pressable, StyleSheet, Text, View, - type ViewStyle, + type ViewStyle } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; @@ -33,13 +31,9 @@ import { Plus } from 'lucide-react-native'; /** Hauteur de la barre hors safe area. La hauteur réelle y ajoute l'inset bas. */ export const TAB_BAR_BASE_HEIGHT = 52; -const FAB_SIZE = 62; - -/** - * expo-blur ne rend rien d'exploitable sous Android 9 : sans ce repli on - * obtient un rectangle transparent et des libellés illisibles. - */ -const SUPPORTS_BLUR = Platform.OS === 'ios' || Number(Platform.Version) >= 28; +const FAB_SIZE = 72; +const FAB_RADIUS = 24; +const FAB_LIFT = 40; type ExpoRouterTabBarProps = Parameters< NonNullable['tabBar']> @@ -88,18 +82,13 @@ export function BahlaTabBar({ ); return ( - @@ -112,24 +101,28 @@ export function BahlaTabBar({ if (fabRouteName && route.name === fabRouteName) { return ( + [ - styles.fab, - pressed && styles.fabPressed, - ]} + style={styles.fabPressable} > - - - + {({ pressed }) => ( + + + + )} + ); } @@ -181,7 +174,7 @@ export function BahlaTabBar({ ); })} - + ); } @@ -237,41 +230,51 @@ const styles = StyleSheet.create({ /* Le créneau central est plus étroit que les onglets : 84 px fixes, comme la colonne du même nom dans la maquette. */ fabSlot: { - width: 84, + width: 96, alignItems: 'center', + overflow: 'visible', + zIndex: 20, }, - fab: { + fabShell: { width: FAB_SIZE, height: FAB_SIZE, aspectRatio: 1, - borderRadius: 15, + borderRadius: FAB_RADIUS, // Remonte au-dessus de la barre et découpe un anneau dans le fond. - marginTop: -30, + marginTop: -FAB_LIFT, overflow: 'hidden', alignSelf: 'center', + zIndex: 20, borderWidth: 3, borderColor: colors.deepBackground, shadowColor: colors.primary, - shadowOffset: { width: 0, height: 14 }, - shadowOpacity: 0.85, - shadowRadius: 17, - elevation: 12, + shadowOffset: { width: 0, height: 16 }, + shadowOpacity: 0.9, + shadowRadius: 20, + elevation: 18, }, - fabPressed: { - transform: [{ scale: 0.94 }], - shadowOpacity: 0.5, + fabPressable: { + width: '100%', + height: '100%', + borderRadius: FAB_RADIUS, + overflow: 'hidden', }, fabGradient: { width: '100%', height: '100%', aspectRatio: 1, - borderRadius: 15, + borderRadius: FAB_RADIUS, alignItems: 'center', justifyContent: 'center', }, + + fabGradientPressed: { + transform: [{ scale: 0.96 }], + opacity: 0.92, + }, }); export default BahlaTabBar; diff --git a/src/components/organizer/CreateActionSheet.tsx b/src/components/organizer/CreateActionSheet.tsx index 3ec5ad7..c03b834 100644 --- a/src/components/organizer/CreateActionSheet.tsx +++ b/src/components/organizer/CreateActionSheet.tsx @@ -4,18 +4,18 @@ * ------------------------------------------------------------------ */ import { LinearGradient } from 'expo-linear-gradient'; import { - Modal, - Pressable, - StyleSheet, - Text, - View, - type ViewStyle, + Modal, + Pressable, + StyleSheet, + Text, + View, + type ViewStyle, } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { colors, gradientDirection, gradients } from '@/theme/colors'; import { typography } from '@/theme/typography'; -import { Plus } from 'lucide-react-native'; +import { MessageSquare, Plus } from 'lucide-react-native'; type Props = { visible: boolean; @@ -32,6 +32,7 @@ export function CreateActionSheet({ }: Props) { const insets = useSafeAreaInsets(); + /* TODO - rendre dynamique en fonction du club connecté */ return ( + + + Créer - Club Vertige + + + + [styles.row, pressed && styles.rowPressed]} + style={styles.rowPressable} > - - - - - Créer un événement - Date, lieu, line-up, billetterie - + {({ pressed }) => ( + + + + + + Créer un événement + Date, lieu, line-up, billetterie + + + )} [styles.row, pressed && styles.rowPressed]} + style={styles.rowPressable} > - - - - - Publier un post - Sur un de tes événements à venir - + {({ pressed }) => ( + + + + + + Publier un post + Sur un de tes événements à venir + + + )} @@ -117,7 +138,13 @@ const styles = StyleSheet.create({ borderColor: colors.border, }, - rowPressed: { opacity: 0.7 }, + rowPressable: { + borderRadius: 18, + }, + + rowPressed: { + opacity: 0.7, + }, iconBox: { width: 48, @@ -133,6 +160,13 @@ const styles = StyleSheet.create({ borderColor: colors.border, }, + modalTitle: { + ...typography.sectionLabel, + color: colors.textPrimary, + fontSize: 14, + marginBottom: 10, + }, + rowText: { flex: 1, gap: 2 }, rowTitle: { diff --git a/src/components/ui/Header.tsx b/src/components/ui/Header.tsx new file mode 100644 index 0000000..2c0c8ab --- /dev/null +++ b/src/components/ui/Header.tsx @@ -0,0 +1,91 @@ +/* ------------------------------------------------------------------ * + * Header — trois variantes : large, compact, overlay. + * ------------------------------------------------------------------ */ +import { useRouter } from 'expo-router'; +import { ChevronLeft } from 'lucide-react-native'; +import { ReactNode } from 'react'; +import { Pressable, StyleSheet, Text, View } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; + +import { colors } from '@/theme/colors'; +import { typography } from '@/theme/typography'; + +type Props = { + title?: string; + /** Overline mono au-dessus du titre (variante large uniquement). */ + overline?: string; + variant?: 'large' | 'compact' | 'overlay'; + /** Flèche retour. Auto : true sauf en `large`. */ + back?: boolean; + onBack?: () => void; + /** Actions à droite — icônes 44×44 déjà encapsulées par l'appelant. */ + right?: ReactNode; +}; + +export function Header({ title, overline, variant = 'large', back, onBack, right }: Props) { + const router = useRouter(); + const insets = useSafeAreaInsets(); + const showBack = back ?? variant !== 'large'; + const glass = variant === 'overlay'; + + return ( + + {showBack && ( + router.back())} + style={[styles.iconButton, glass && styles.iconButtonGlass]} + > + + + )} + + + {overline && variant === 'large' && {overline}} + {title && ( + + {title} + + )} + + + {right ?? (showBack && variant === 'compact' ? : null)} + + ); +} + +const styles = StyleSheet.create({ + row: { flexDirection: 'row', alignItems: 'center', gap: 12, paddingTop: 6, paddingBottom: 14 }, + compactRow: { paddingBottom: 10 }, + absolute: { position: 'absolute', top: 0, left: 0, right: 0, zIndex: 10, paddingHorizontal: 20 }, + + titleWrap: { flex: 1, minWidth: 0, gap: 2 }, + titleWrapCentered: { alignItems: 'center' }, + overline: { ...typography.overlineSm, color: colors.textSecondary }, + titleLarge: { ...typography.screenTitleLg, color: colors.textPrimary }, + titleCompact: { ...typography.cardTitle, color: colors.textPrimary }, + + iconButton: { + width: 44, + height: 44, + borderRadius: 14, + backgroundColor: colors.surface, + borderWidth: 1, + borderColor: colors.border, + alignItems: 'center', + justifyContent: 'center', + }, + iconButtonGlass: { backgroundColor: colors.glassFill, borderColor: 'transparent' }, + spacer: { width: 44 }, +}); \ No newline at end of file diff --git a/src/components/ui/Screen.tsx b/src/components/ui/Screen.tsx new file mode 100644 index 0000000..41d39b0 --- /dev/null +++ b/src/components/ui/Screen.tsx @@ -0,0 +1,75 @@ +/* ------------------------------------------------------------------ * + * Screen — enveloppe d'écran. Fond, zone sûre, padding de tab bar. + * ------------------------------------------------------------------ */ +import { ReactNode } from 'react'; +import { ScrollView, StyleSheet, View, ViewStyle } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; + +import { colors } from '@/theme/colors'; + +/** Hauteur de la tab bar custom, hors safe-area. Source unique. */ +import { TAB_BAR_BASE_HEIGHT } from '@/components/navigation/BahlaTabBar'; +export const TAB_BAR_HEIGHT = TAB_BAR_BASE_HEIGHT; + +type Props = { + children: ReactNode; + /** `scroll` enveloppe dans un ScrollView, `static` en View simple. */ + layout?: 'scroll' | 'static'; + /** Applique le padding haut de la zone sûre. false pour un écran à image plein bord. */ + edgeToEdge?: boolean; + /** Réserve la hauteur de la tab bar en bas. false sur les écrans modaux / (org)/create. */ + tabBar?: boolean; + /** Halo violet décoratif en haut à gauche (B1, C1). */ + halo?: boolean; + /** Padding horizontal des enfants. 20 par défaut, 0 pour du plein bord. */ + gutter?: number; + contentContainerStyle?: ViewStyle; +}; + +export function Screen({ + children, + layout = 'scroll', + edgeToEdge = false, + tabBar = true, + halo = false, + gutter = 20, + contentContainerStyle, +}: Props) { + const insets = useSafeAreaInsets(); + + const padding: ViewStyle = { + paddingTop: edgeToEdge ? 0 : insets.top, + paddingHorizontal: gutter, + paddingBottom: tabBar ? TAB_BAR_HEIGHT + insets.bottom + 24 : insets.bottom + 24, + }; + + return ( + + {halo && } + {layout === 'scroll' ? ( + + {children} + + ) : ( + {children} + )} + + ); +} + +const styles = StyleSheet.create({ + root: { flex: 1, backgroundColor: colors.deepBackground }, + flex: { flex: 1 }, + halo: { + position: 'absolute', + width: 380, + height: 380, + borderRadius: 190, + top: -140, + left: -60, + backgroundColor: colors.secondarySoft, + }, +}); \ No newline at end of file diff --git a/src/global.css b/src/global.css deleted file mode 100644 index bd6213e..0000000 --- a/src/global.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; \ No newline at end of file diff --git a/src/stores/authStore.ts b/src/stores/authStore.ts index 4ba9d05..bbb0de9 100644 --- a/src/stores/authStore.ts +++ b/src/stores/authStore.ts @@ -13,7 +13,7 @@ const DEV_MOCK_SESSION_ENABLED = true; const DEV_MOCK_SESSION: Session = { userId: 'dev-user', token: 'dev-token', - role: 'org', + role: 'user', }; type AuthState = { diff --git a/tailwind.config.js b/tailwind.config.js deleted file mode 100644 index d27d790..0000000 --- a/tailwind.config.js +++ /dev/null @@ -1,10 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ["src/**/*.{html,js,ts,jsx,tsx}"], - presets: [require("nativewind/preset")], - theme: { - extend: {}, - }, - plugins: [], -} -