Creative Code

Aurora-(12)최종 프로젝트 1 - 소개, 로그인,회원가입,비밀번호찾기, 홈화면 구성 본문

Projects

Aurora-(12)최종 프로젝트 1 - 소개, 로그인,회원가입,비밀번호찾기, 홈화면 구성

빛하루 2023. 11. 28. 18:05

※설치 프로그램 : node.js 20.9 버전

vscode,anaconda (python 3.11.5)버전

 

※사용한 라이브러리 : Reflex

※설치 명령어 : 

 

pip install reflex

pip install geopy

pip install folium

pip install PyKakao

pip install BeautifulSoup

 

reflex init

reflex db makemigrations

reflex db migrate

reflex run

 

Aurora 로그인 첫 화면

 

--> username과 password를 입력하면 데이터 베이스에 저장된 유저들의 정보와 비교해 일치하면 로그인 가능, 불일치하면 로그인 실패 기능

 

※로그인 화면(front-end)을 구성하는 코드(pages/login.py)

# 로그인 페이지. auth_layout을 사용하여 회원가입 페이지와 공유되는 UI를 렌더링합니다.
import reflex as rx

from aurora.state.auth import AuthState

def login():
    return rx.container(
        # 상단 여백을 추가한 컨테이너
        rx.container(height='200px'), 
        
        # 세로로 쌓인 요소들을 가로로 묶은 컨테이너
        rx.vstack(
            # 로고와 제목이 있는 가로로 묶인 컨테이너
            rx.hstack(
                # 로고를 담은 세로로 쌓인 컨테이너
                rx.vstack(
                    rx.container(height='20px'),  # 상단 여백
                    rx.image(
                        src="/aurora.ico",
                        width="70px",
                        height="70px",
                    ),
                ),              
                # 제목과 부제목이 있는 세로로 쌓인 컨테이너
                rx.vstack(           
                    rx.container(height='8px'),  # 상단 여백
                    rx.container(
                        # "AURORA" 제목
                        rx.text(
                            "AURORA",
                            style={
                                "fontSize": "40px",
                                "fontWeight": "bolder",
                                "letterSpacing": "3px",
                                "fontFamily": "Open Sans, Sans-serif",
                                "background": "-webkit-linear-gradient(-45deg, #e04a3f, #4e8be6)",
                                "-webkit-background-clip": "text",
                                "color": "black",
                            },
                            mb=-3,
                        ),
                        # 부제목
                        rx.text(
                            "Record your shining moments!",
                            style={
                                'background': "-webkit-linear-gradient(-45deg, #e04a3f, #4e8be6)",
                                'background_clip': "text",  # 텍스트에만 그라데이션 적용
                                'color': "transparent",  # 텍스트 색상을 투명으로 설정
                                'font_weight': "medium",
                            },
                        ),
                    ),
                ),
            ),
            
            # 로그인 폼이 있는 세로로 쌓인 컨테이너
            rx.container(
                rx.vstack(
                    rx.container(
                        rx.input(placeholder="Username", on_blur=AuthState.set_username, mb=4),
                        rx.input(
                            type_="password",
                            placeholder="Password",
                            on_blur=AuthState.set_password,
                            mb=4,
                        ),
                        rx.button(
                            "Log in",
                            on_click=AuthState.login,
                            bg="#212963",
                            color="white",
                            _hover={"bg": "blue.600"},
                        ),
                        center_content=True,
                        align_items="left",
                        bg="white",
                        border="1px solid #eaeaea",
                        p=4,
                        max_width="400px",
                        border_radius="lg",
                    ),
                    
                    rx.container(height='10px'),
                    
                    # 비밀번호 찾기 링크와 회원가입 링크가 있는 컨테이너
                    rx.text(
                        'Forgot your password?   ',
                        rx.link('Find Password!', href="/findpassword", color='green.500'),
                        color="gray.600",
                    ), 
                    rx.text(
                        "Don't have an account yet?   ",
                        rx.link("Sign up!", href="/signup", color="blue.500"),
                        color="gray.600",
                    ),
                    
                    rx.container(height='30px'),  # 하단 여백
                ),
            ),
            
            # 로그인 폼을 감싸는 외부 컨테이너
            width='400px',
            height='auto',
            center_content=True,
            borderRadius='20px',
            boxShadow='10px 10px 100px #79d0ed',
            background="linear-gradient(to bottom, #d7eefc, #ffffff)"
        ),
        
        # 전체 페이지를 감싸는 컨테이너
        center_content=True,
        maxWidth='auto',
        maxHeight='auto',
        height='100vh',
        style={
            'background-image':"url('/aurora1.jpg')",  # 배경 이미지 설정
            'background-size':'cover',
        }
    )

 

 

 

 

Aurora 회원 가입 화면

 

--> 회원가입시 데이터베이스에 저장된 유저들의 정보와 비교해 같은 아이디가 있을 시 해당 아이디로 가입불가능, 회원가입시 비밀번호는 최소 4자리 이상으로 구성할 수 있도록 구성, 회원가입 성공시 데이터베이스에 유저정보 저장 및 바로 홈 화면으로 이동 가능

 

※ 회원 가입 화면 (front-end) 을 구성하는 코드 (pages/signup.py)

# 회원가입 페이지. 로그인 페이지와 공유되는 UI를 렌더링하기 위해 auth_layout을 사용합니다.
import reflex as rx
from aurora.state.auth import AuthState

def signup():
    """회원가입 페이지."""
    return rx.container(
        # 상단 여백을 추가한 컨테이너
        rx.container(height='210px'),
        
        # 세로로 쌓인 요소들을 가로로 묶은 컨테이너
        rx.vstack(
            # 로고와 제목이 있는 가로로 묶인 컨테이너
            rx.hstack(
                # 로고를 담은 세로로 쌓인 컨테이너
                rx.vstack(
                    rx.container(height='20px'),  # 상단 여백
                    rx.image(
                        src="/aurora.ico",
                        width="70px",
                        height="70px",
                    ),
                ),              
                # 제목과 부제목이 있는 세로로 쌓인 컨테이너
                rx.vstack(           
                    rx.container(height='8px'),  # 상단 여백
                    rx.container(
                        # "AURORA" 제목
                        rx.text(
                            "AURORA",
                            style={
                                "fontSize": "40px",
                                "fontWeight": "bolder",
                                "letterSpacing": "3px",
                                "fontFamily": "Open Sans, Sans-serif",
                                "background": "-webkit-linear-gradient(-45deg, #e04a3f, #4e8be6)",
                                "-webkit-background-clip": "text",
                                "color": "black",
                            },
                            mb=-3,
                        ),
                        # 부제목
                        rx.text(
                            "Record your shining moments!",
                            style={
                                'background': "-webkit-linear-gradient(-45deg, #e04a3f, #4e8be6)",
                                'background_clip': "text",  # 텍스트에만 그라데이션 적용
                                'color': "transparent",  # 텍스트 색상을 투명으로 설정
                                'font_weight': "medium",
                            },
                        ),
                    ),
                ),
            ),
            
            rx.container(height='10px'),  # 중간 여백
            
            # 회원가입 폼이 있는 컨테이너
            rx.container(
                rx.input(placeholder="Username", on_blur=AuthState.set_username, mb=4),
                rx.input(
                    type_="password",
                    placeholder="Password",
                    on_blur=AuthState.set_password,
                    mb=4,
                ),
                rx.input(
                    type_="password",
                    placeholder="Confirm password",
                    on_blur=AuthState.set_confirm_password,
                    mb=4,
                ),
                rx.button(
                    "Sign up",
                    on_click=AuthState.signup,
                    bg="#212963",
                    color="white",
                    _hover={"bg": "blue.600"},
                ),
                align_items="left",
                bg="white",
                border="1px solid #eaeaea",
                p=4,
                max_width="400px",
                border_radius="lg",
            ),
            
            rx.container(height='10px'),  # 중간 여백
            
            # 로그인 페이지로 이동하는 링크와 함께 메시지를 표시하는 컨테이너
            rx.text(
                "Already have an account? ",
                rx.link("Sign in here.", href="/", color="blue.500"),
                color="gray.600",
            ),
            
            rx.container(height='20px'),  # 하단 여백
            
            # 외부 컨테이너 속성 설정
            width='400px',
            height='auto',
            center_content=True,
            borderRadius='20px',
            boxShadow='9px 9px 100px #79d0ed',
            background="linear-gradient(to bottom, #d7eefc, #ffffff)"
        ),
        
        # 전체 페이지를 감싸는 컨테이너 속성 설정
        center_content=True,
        maxWidth='auto',
        maxHeight='auto',
        height='100vh',
        style={
            'background-image':"url('/aurora1.jpg')",  # 배경 이미지 설정
            'background-size':'cover',
        }
    )

 

 

 

비밀번호 찾기 화면

--> 아이디 입력시 비밀번호 찾기 기능 제공 (팝업으로 비밀번호 제공 -> 향후 힌트 형식으로 변경가능)

 

※ 비밀번호 찾기 화면(front-end) 을 구성하는 코드(pages/findpassword.py)

# 비밀번호 찾기 페이지. 로그인 페이지와 공유되는 UI를 렌더링하기 위해 auth_layout을 사용합니다.
import reflex as rx
from aurora.state.auth import AuthState

def findpassword():
    """비밀번호 찾기 페이지."""
    return rx.container(
        # 상단 여백을 추가한 컨테이너
        rx.container(height='200px'),
        
        # 세로로 쌓인 요소들을 가로로 묶은 컨테이너
        rx.vstack(
            # 로고와 제목이 있는 가로로 묶인 컨테이너
            rx.hstack(
                # 로고를 담은 세로로 쌓인 컨테이너
                rx.vstack(
                    rx.container(height='20px'),  # 상단 여백
                    rx.image(
                        src="/aurora.ico",
                        width="70px",
                        height="70px",
                    ),
                ),              
                # 제목과 부제목이 있는 세로로 쌓인 컨테이너
                rx.vstack(           
                    rx.container(height='8px'),  # 상단 여백
                    rx.container(
                        # "AURORA" 제목
                        rx.text(
                            "AURORA",
                            style={
                                "fontSize": "40px",
                                "fontWeight": "bolder",
                                "letterSpacing": "3px",
                                "fontFamily": "Open Sans, Sans-serif",
                                "background": "-webkit-linear-gradient(-45deg, #e04a3f, #4e8be6)",
                                "-webkit-background-clip": "text",
                                "color": "black",
                            },
                            mb=-3,
                        ),
                        # 부제목
                        rx.text(
                            "Record your shining moments!",
                            style={
                                'background': "-webkit-linear-gradient(-45deg, #e04a3f, #4e8be6)",
                                'background_clip': "text",  # 텍스트에만 그라데이션 적용
                                'color': "transparent",  # 텍스트 색상을 투명으로 설정
                                'font_weight': "medium",
                            },
                        ),
                    ),
                ),
            ),
            
            rx.container(height='10px'),  # 중간 여백
            
            # 비밀번호 찾기 폼이 있는 컨테이너
            rx.container(
                rx.input(placeholder="Username", on_blur=AuthState.set_username, mb=4),
                rx.button(
                    "Find Password",
                    on_click=AuthState.findpassword,
                    bg="#212963",
                    color="white",
                    _hover={"bg": "blue.600"},
                ),
                align_items="left",
                bg="white",
                border="1px solid #eaeaea",
                p=4,
                max_width="400px",
                border_radius="lg",
            ),
            
            rx.container(height='10px'),  # 중간 여백
            
            # 로그인 페이지로 이동하는 링크와 함께 메시지를 표시하는 컨테이너
            rx.text(
                "Already have an account? ",
                rx.link("Sign in here.", href="/", color="blue.500"),
                color="gray.600",
            ),
            
            rx.container(height='20px'),  # 하단 여백
            
            # 외부 컨테이너 속성 설정
            width='400px',
            height='auto',
            center_content=True,
            borderRadius='20px',
            boxShadow='9px 9px 100px #79d0ed',
            background="linear-gradient(to bottom, #d7eefc, #ffffff)"
        ),
        
        # 전체 페이지를 감싸는 컨테이너 속성 설정
        center_content=True,
        maxWidth='auto',
        maxHeight='auto',
        height='100vh',
        style={
            'background-image':"url('/aurora1.jpg')",  # 배경 이미지 설정
            'background-size':'cover',
        }
    )

 

 

 

 

 

홈화면

--> select 파일버튼을 클릭하면 내 파일에서 이미지 파일을 골라 글을 작성한뒤 업로드 기능(select cancel버튼을 누르면 업로드한 파일선택 취소기능), 맨위 검색창에서 aurora 를 입력하면 aurora 단어가 포함된 게시글만 표시 가능, 오른쪽 search users에서 haru로 검색하면 haru라는 글자가 포함된 유저목록 검색가능,  왼쪽 탭에서 my proflle, Maps, viedo 등 버튼을 누르면 해당 링크로 이동 가능, sign out버튼을 누르면 로그아웃 기능, 달모양 버튼을 누르면 다크모드 설정 가능

 

※홈 화면(front-end)를 구성하는 코드 : pages/home.py

# aurora.state.home 모듈에서 필요한 State 및 HomeState를 가져옵니다.
import reflex as rx
from aurora.state.base import State
from aurora.state.home import HomeState

# 컴포넌트를 가져옵니다.
from ..components import container

color = "rgb(107,99,246)"

# 탭 버튼을 생성하는 함수
def tab_button(name, href):
    """탭 전환 버튼 생성 함수."""
    return rx.link(
        rx.icon(tag="star", mr=2),  # 별 모양 아이콘
        name,  # 버튼 텍스트
        display="inline-flex",
        align_items="center",
        py=3,
        px=6,
        href=href,  # 버튼 클릭 시 이동할 경로
        border="1px solid #000000",
        font_weight="semibold",
        border_radius="full",
    )

# 왼쪽에 표시되는 탭 스위처
def tabs():
    """왼쪽에 표시되는 탭 스위처."""
    return rx.box(
        rx.vstack(
            rx.container(
                rx.hstack(
                    rx.icon(tag="moon", mr=2, color='yellow'),  # 달 모양 아이콘
                    rx.text(
                        "Aurora", 
                        style={
                            "fontSize": "25px",
                            "fontWeight": "bolder",
                            "fontFamily": "Open Sans,Sans-serif",
                            "background": "-webkit-linear-gradient(-45deg, #e04a3f, #4e8be6)",
                            "-webkit-background-clip": "text",
                            "color": "transparent",
                        },
                        center_content=True,
                    ),  # 앱 이름
                ),
            ),
            tab_button("Home", "/"),  # Home 탭 버튼
            tab_button("My Profile","/myprofile"),
            tab_button("Maps","/maps"),
            tab_button("video","/video"),
            tab_button("web search","/websearch"),
            tab_button("ai chat","/aichat"),
            tab_button("talk","/talk"),
            rx.button("Sign out", on_click=State.logout),  # 로그아웃 버튼
            rx.button(
                rx.icon(tag="moon"),
                on_click=rx.toggle_color_mode,
            ),
            rx.container(height='200px'),
            align_items="left",
            gap=4,
        ),
        py=4,
    )

# 오른쪽에 표시되는 사이드바
def sidebar(HomeState):
    """오른쪽에 표시되는 사이드바."""
    return rx.vstack(
        rx.input(
            on_change=HomeState.set_friend,
            placeholder="Search users",  # 사용자 검색을 위한 입력 상자
            width="100%",
            border = "3px solid #000000",
        ),
        rx.foreach(
            HomeState.search_users,
            lambda user: rx.vstack(
                rx.hstack(
                    rx.avatar(name=user.username, size="sm"),  # 검색된 사용자의 아바타 이미지
                    rx.text(user.username),  # 검색된 사용자의 사용자 이름
                    rx.spacer(),
                    rx.button(
                        rx.icon(tag="add"),
                        on_click=lambda: HomeState.follow_user(user.username),  # 사용자를 팔로우하는 버튼
                    ),
                    width="100%",
                ),
                py=2,
                width="100%",
            ),
        ),
        align_items="start",
        gap=4,
        h="100%",
        py=4,
    )

# 피드의 헤더
def feed_header(HomeState):
    """피드의 헤더."""
    return rx.hstack(
        rx.heading("Story", size="md"),  # 피드의 제목
        rx.input(on_change=HomeState.set_search, placeholder="Search tweets"),  # 트윗 검색을 위한 입력 상자
        justify="space-between",
        p=4,
        border_bottom="3px solid #000000",
    )

# 새로운 트윗을 작성하는 컴포저
def composer(HomeState):
    """새로운 트윗을 작성하는 컴포저."""
    return rx.vstack(
        rx.container(height='5px'),
        rx.vstack(
            rx.hstack(
                rx.avatar(size="md"),  # 사용자의 아바타 이미지
                rx.container(width='30px'),
                rx.text_area(
                    value=HomeState.tweet,
                    w='100%',
                    border=2,
                    placeholder="What's happening?",