Компоненты/Заставка

Заставка

31 января 2025

Анимированная радиальная заставка по мотивам react-bits

Установка

npx astra-rn add radial-intro
pnpm dlx astra-rn add radial-intro
yarn dlx astra-rn add radial-intro
bunx --bun astra-rn add radial-intro

Файлы

index.tsx
НазадРадиальная схемаДалееРадиальное раскрытие

Вручную

Поставьте зависимости:

npm install expo-blur react-native-reanimated
pnpm add expo-blur react-native-reanimated
yarn add expo-blur react-native-reanimated
bun add expo-blur react-native-reanimated

Скопируйте эти файлы в src/shared/components/organisms/radial-intro/:

Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.

Использование

import { StyleSheet, Text, View } from "react-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { StatusBar } from "expo-status-bar";
import { useMemo, useRef, useState } from "react";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { RadialIntro, OrbitItem } from "@/shared/components/organisms/radial-intro";
import { Showcase, useAutoplay, useCustomize } from "~/showcase";
import { PHOTO_SOURCES } from "~/assets/photos";

const ORBIT_ITEMS: OrbitItem[] = [
  {
    id: 1,
    src: PHOTO_SOURCES["radial-intro-1"],
  },
  {
    id: 2,
    src: PHOTO_SOURCES["radial-intro-2"],
  },
  {
    id: 3,
    src: PHOTO_SOURCES["radial-intro-3"],
  },
  {
    id: 4,
    src: PHOTO_SOURCES["radial-intro-4"],
  },
  {
    id: 5,
    src: PHOTO_SOURCES["radial-intro-5"],
  },
];

const CUSTOMIZE = [
  { key: "photos", label: "Изображения", type: "images", default: ORBIT_ITEMS.map((item) => item.src) },
  { key: "stageSize", label: "Размер сцены", type: "slider", min: 260, max: 420, step: 2, unit: "px", default: 400 },
  { key: "imageSize", label: "Размер фото", type: "slider", min: 50, max: 140, step: 1, unit: "px", default: 90 },
  { key: "spinDuration", label: "Период вращения", type: "slider", min: 2, max: 40, step: 1, unit: "s", default: 12 },
  { key: "revealOnFanOut", label: "Показ при раскрытии", type: "toggle", default: false },
  { key: "background", label: "Фон", type: "color", default: "#0a0a0a" },
] as const;

export default function App() {
  const custom = useCustomize(CUSTOMIZE);
  const orbitItems = useMemo(
    () => ORBIT_ITEMS.map((item, index) => ({ ...item, src: custom.photos[index] ?? item.src })),
    [custom.photos],
  );
  const insets = useSafeAreaInsets();
  const [expanded, setExpanded] = useState(false);
  const expandedRef = useRef(expanded);
  expandedRef.current = expanded;

  useAutoplay(async ({ wait }) => {
    if (!expandedRef.current) {
      await wait(550);
      setExpanded(true);
    }
    await wait(5900);
    setExpanded(false);
    await wait(450);
  });

  return (
    <Showcase>
      <GestureHandlerRootView
        style={[styles.container, { paddingBottom: insets.top, backgroundColor: custom.background }]}
      >
        <StatusBar style="light" />

        <View style={styles.card}>
          <RadialIntro
            orbitItems={orbitItems}
            expanded={expanded}
            stageSize={custom.stageSize}
            revealOnFanOut={custom.revealOnFanOut}
            imageSize={custom.imageSize}
            spinDuration={custom.spinDuration}
            onCenterPress={() => setExpanded((v) => !v)}
          />
        </View>
      </GestureHandlerRootView>
    </Showcase>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#0a0a0a",

    alignItems: "center",
    justifyContent: "center",
    overflow: "hidden",
  },

  card: {},

  caption: {
    marginTop: 18,
    fontSize: 13,
    color: "rgba(255,255,255,0.55)",
    letterSpacing: -0.2,
  },
});

Пропсы

Пропс
Описание
orbitItems

Тип readonly OrbitItem[]

stageSize?

Тип number

imageSize?

Тип number

spinDuration?

Тип number

expanded?

Тип boolean

onCenterPress?

Тип () => void

revealOnFanOut?

Тип boolean

style?

Тип StyleProp<ViewStyle>