퀴즈앱 개발기/RN

퀴즈앱 6일차

시우진석 2024. 6. 26. 19:33
반응형

오늘은 간단하게 디자인중입니다. 

디자인에 자신이 없기 때문에 인터넷의 도움을 받아봅시다.

 

우선 아래 링크에서 원하는 색상조합을 골랐습니다.

 

색상 팔레트: #850F8D #C738BD #E49BFF #F8F9D7 - 컬러 헌트 (colorhunt.co)

 

Color Palette: #850F8D #C738BD #E49BFF #F8F9D7 - Color Hunt

Discover the newest hand-picked color palettes of Color Hunt. Get color inspiration for your design and art projects.

colorhunt.co

 

 

다음으로는 아래 사이트에서 우주관련된 이미지를 받아왔습니다.

 

20+ 우주 사진 및 이미지 [HD] | Unsplash에서 무료 사진 다운로드

 

20+ 우주 사진 및 이미지 [HD] | Unsplash에서 무료 사진 다운로드

완벽한 우주 사진을 다운로드하세요. 100개가 넘는 최고의 무료 우주 이미지를 찾아 보세요. 상용으로 무료 사용 가능 ✓ 저작자 표시 불필요 ✓ 저작권 없음 ✓

unsplash.com

 

 

자 이제 빠르게 개발해봅시다. 

 

우선 홈부터 개발해봅시다.

 

저는 첫 페이지의 배경을 색상이 아닌 사진으로 채워 넣기 위해 backgroundImage를 쓰면 될 줄 알았지만,

직접 하려니 안되더군요 그래서 찾아보니

 

Set a component's background image - Expo Documentation

 

Set a component's background image

Learn how to use ImageBackground component to set a component's background image.

docs.expo.dev

 

이렇게 ImageBackground라는 컴포넌트가 있더군요.

 

바로 사용해봅시다.

 

저는 사진을 assets/img/mainbg.jpg 이렇게 넣어둬서 아래처럼 작성하면 되더군요!

<ImageBackground
        source={require("../assets/img/mainbg.jpg")}
        style={styles.bg}
      >
</ImageBackground>

 

 

자 다음은 게임들을 보면 아무곳이나 터치하면 다음으로 넘어가잖아요?

터치하면 로그인페이지로 넘어가게 Link 컴포넌트를 사용해봤는데 디자인이 이상해지더라구요.

 

그래서 gpt찬스를 썼더니 아래처럼 작성하면 된다고 하네요 ㅎㅎ

<Link
  href={{
  	pathname: "/login",
  }}
  asChild
  >
   <Pressable style={styles.linkContainer}>
      <Header />
      <View style={styles.touchMeContainer}>
        <Text style={styles.touchMeText}> Please touch anywhere!! </Text>
      </View>
   </Pressable>
</Link>

 

자 확인해볼까요?

 

 

 

나름 그럴듯 해보이죠?! 

 

전체 코드입니당~

import { Link } from "expo-router";
import { StatusBar } from "expo-status-bar";
import {
  ImageBackground,
  Pressable,
  StyleSheet,
  Text,
  View,
} from "react-native";
import Header from "./_components/Header";
import { BASE_COLOR } from "../assets/constants/color";

export default function App() {
  return (
    <View style={styles.main}>
      <ImageBackground
        source={require("../assets/img/mainbg.jpg")}
        style={styles.bg}
      >
        <Link
          href={{
            pathname: "/login",
          }}
          asChild
        >
          <Pressable style={styles.linkContainer}>
            <Header />
            <View style={styles.touchMeContainer}>
              <Text style={styles.touchMeText}> Please touch anywhere!! </Text>
            </View>
          </Pressable>
        </Link>
      </ImageBackground>

      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  main: {
    flex: 1,
  },
  linkContainer: {
    paddingVertical: 50,
    flex: 1,
  },
  bg: {
    flex: 1,
  },
  touchMeContainer: {
    flex: 1,
    alignItems: "center",
    justifyContent: "flex-end",
  },
  touchMeText: {
    color: BASE_COLOR.DEEP,
    fontSize: 20,
  },
  title: {
    fontSize: 30,
    fontWeight: "bold",
    color: BASE_COLOR.LIGHT_TEXT,
  },
});

 

헤더 코드는 아래 남겨두겠습니다!

 

import { StyleSheet, Text, View } from "react-native";

export default function Header() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Quiz Galaxy Planet !</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "flex-start",
    marginTop: 50,
  },
  title: {
    fontSize: 30,
    fontWeight: "bold",
    color: "#F8F9D7",
  },
});

 

이제 로그인 페이지도 간단하게 디자인 해보겠습니다~

 

우선 inputBox 부터 만들어볼게요. 

재사용하면 좋을 것 같아서 assets/components 폴더에 만들었습니다.

 

저는 아래처럼 만들어 봤습니다!

타입이 있지 않을까해서 자동완성으로 찾아보니 TextInputProps라는 친구가 있더라구요!

import {
  View,
  Text,
  TextInput,
  StyleSheet,
  TextInputProps,
} from "react-native";
import React from "react";
import { BASE_COLOR } from "../../constants/color";

interface InputBoxProps extends TextInputProps {
  labelName: string;
}

export default function InputBox({ labelName, ...rest }: InputBoxProps) {
  return (
    <View style={styles.container}>
      <Text style={styles.label}>{labelName}</Text>
      <TextInput
        autoCapitalize="none"
        placeholderTextColor={BASE_COLOR.LIGHT}
        style={styles.input}
        {...rest}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    paddingHorizontal: 20,
  },
  input: {
    paddingVertical: 15,
    paddingHorizontal: 20,
    backgroundColor: BASE_COLOR.MEDIUM,
    padding: 10,
    borderWidth: 1,
    borderColor: BASE_COLOR.LIGHT,
    marginBottom: 10,
    borderRadius: 15,
    color: BASE_COLOR.LIGHT_TEXT,
  },
  label: {
    color: BASE_COLOR.LIGHT_TEXT,
    marginBottom: 8,
  },
});

 

그리고 로그인 로직이 들어갈 LoginForm 컴포넌트를 만들어봤습니다.

 

import { View, Text, StyleSheet, Pressable } from "react-native";
import React, { useState } from "react";
import InputBox from "../../../assets/components/Input/InputBox";
import { BASE_COLOR } from "../../../assets/constants/color";
import { Link } from "expo-router";
import {
  checkEmail,
  checkPassword,
} from "../../../assets/utils/checkSignMessage";

export default function LoginForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const submitLogin = async () => {
    const checkedEmail = checkEmail(email);
    const checkedPassword = checkPassword(password);

    if (checkedEmail !== "") {
      alert(checkedEmail);
      return;
    }

    if (checkedPassword !== "") {
      alert(checkedPassword);
      return;
    }

    console.log(email, password);
  };
  return (
    <View style={styles.form}>
      <InputBox
        labelName="이메일"
        placeholder="이메일을 입력해주세요"
        value={email}
        onChangeText={(value: string) => setEmail(value)}
        onSubmitEditing={submitLogin}
      />
      <InputBox
        labelName="비밀번호"
        placeholder="비밀번호를 입력해주세요"
        value={password}
        onChangeText={(value: string) => setPassword(value)}
        onSubmitEditing={submitLogin}
        secureTextEntry
      />
      <Pressable style={styles.submitButton} onPress={submitLogin}>
        <Text style={styles.submitButtonText}>로그인</Text>
      </Pressable>

      <Link href={{ pathname: "/signup" }} style={styles.signLinkText}>
        <Text style={styles.signLinkText}>회원가입하러 가기</Text>
      </Link>
    </View>
  );
}

const styles = StyleSheet.create({
  form: {
    flex: 2,
    justifyContent: "flex-start",
  },
  submitButton: {
    backgroundColor: BASE_COLOR.LIGHT,
    padding: 20,
    borderRadius: 15,
    alignItems: "center",
    marginHorizontal: 20,
    marginTop: 30,
  },
  submitButtonText: {
    fontSize: 20,
    color: BASE_COLOR.LIGHT_TEXT,
  },
  signLinkText: {
    color: BASE_COLOR.LIGHT,
    fontSize: 20,
    textAlign: "center",
    padding: 20,
  },
});

 

나중에 api 요청하기 전에 백엔드 부담을 줄여주기 위해 regex를 이용한 함수 하나를 만들어봤습니다.

 

import { AUTH_ERROR_MESSAGE } from "../constants/message";

const EMAIL_REGEX = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/i;
const PASSWORD_REGEX = /^(?=.*[a-zA-Z])(?=.*[0-9]).{8,}$/;

export const checkEmail = (email: string) => {
  if (!email) {
    return AUTH_ERROR_MESSAGE.NOT_EMAIL;
  }

  if (!EMAIL_REGEX.test(email)) {
    return AUTH_ERROR_MESSAGE.INVALID_EMAIL;
  }
  return "";
};

export const checkPassword = (password: string) => {
  if (!password) {
    return AUTH_ERROR_MESSAGE.NOT_PASSWORD;
  }

  if (!PASSWORD_REGEX.test(password)) {
    return AUTH_ERROR_MESSAGE.INVALID_PASSWORD;
  }

  return "";
};

 

이렇게요! 

 

이제 마지막으로 로그인 페이지의 전체 코드를 보여드릴게요!

import { Link } from "expo-router";
import { StyleSheet, Text, View } from "react-native";
import { BASE_COLOR } from "../../assets/constants/color";
import LoginForm from "./_components/LoginForm";

export default function LoginPage() {
  return (
    <View style={styles.container}>
      <View style={styles.logo}>
        <Link
          href={{
            pathname: "/",
          }}
        >
          <Text style={styles.buttonText}>홈으로</Text>
        </Link>
      </View>
      <LoginForm />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: BASE_COLOR.DEEP,
  },
  logo: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
  },
  buttonText: {
    color: BASE_COLOR.LIGHT_TEXT,
    fontSize: 30,
  },
});

 

이렇게 하면 결과는 두근두근~

 

 

짠~ 이런 결과가 나온답니다. 

나중에 홈으로 부분은 로고 이미지로 대체될 예정이고, 디자인은 차차 수정해가는 걸로 합시다 ㅋㅋㅋ

 

오늘은 여기까지하고 내일은 나머지 회원가입 부분과 axios를 깔아서 전에 만든 백엔드와 상호작용 해보겠습니다.

 

 

오늘도 모두 고생하셨습니다! 남은 하루도 잘 마무리하세요!

 

저도, 여러분도 좋은결과가 있었으면 좋겠습니다! 

반응형