131. Custom Links
npm create vue@latest
링크 추가
헤더에 더 많은 링크를 추가해보도록 하겠습니다.
우리는 헤더 컴포넌트 파일에서 계속 작업을 할 것입니다.
이전에는 홈페이지 링크를 about
페이지로 변경했습니다.
이 링크를 홈페이지를 가리키도록 to
속성을 슬래시(/
)로 설정하여 변경할 것입니다. 우리는 이것을 about 페이지로 연결하고 싶지 않습니다. 그것은 단지 예시였습니다. 하지만, about 페이지를 버리고 싶지는 않습니다. 우리는 그것에 대한 링크를 만들 것입니다. 링크 생성 연습을 할 좋은 기회입니다. 템플릿에서 링크들의 비순차 목록으로 스크롤해봅시다. 맨 처음에 새로운 목록 항목을 추가할 것입니다. 그것은 나머지 링크들과 비슷한 HTML 구조를 가질 것입니다. 다음으로, 앵커 요소를 라우터 링크 컴포넌트로 변경할 것입니다. Href 속성은 to 속성으로 변경될 것이고, 경로는 /about이 될 것입니다. 마지막으로, 내부 텍스트는 'about'이라고 할 것입니다. 내비게이션 메뉴에 추가 링크들이 있지만, 우리는 그 페이지들을 만들 때 업데이트할 것입니다. 현재 우리는 두 개의 페이지를 가지고 있습니다. 우리는 또 다른 링크를 만들 것입니다. 링크들의 비순차 목록에서, 'Manage'라는 페이지로의 링크가 있을 것입니다. 다음 섹션에서, 우리는 음악 업로드 처리를 시작할 것입니다. '관리' 페이지는 인증된 사용자들이 그들의 노래를 업로드하고 편집할 수 있게 할 것입니다, 비록 이 섹션에서 페이지를 기능적으로 만들지는 않겠지만, 우리는 그것에 대한 링크를 추가하는 것으로 시작할 것입니다. 우리는 앵커 요소를 라우터 링크 컴포넌트로 변경할 것입니다. 다음으로, href 속성을 to 속성으로 변경할 것입니다. 경로는 /manage로 설정될 것입니다. 현재 이 루트는 존재하지 않으므로, 우리는 그것을 추가해야 할 것입니다. 라우터 파일로 전환하세요. 우리는 경로 배열에 새로운 레코드를 추가할 것입니다. 경로 속성을 manage로 설정할 것입니다. 우리는 이 루트에 대한 컴포넌트를 View 디렉토리 안에 만들어야 할 것입니다. Manage라고 불리는 컴포넌트를 만드세요. 이 디렉토리에 컴포넌트를 정의하는 것은 필수가 아닙니다. View 디렉토리는 애플리케이션의 주요 콘텐츠를 렌더링하기 위한 컴포넌트를 정리하기 위해 만들어졌습니다. 반면에, components 디렉토리는 일반적인 컴포넌트를 위한 것입니다. 우리는 모든 것을 한 디렉토리에 넣을 수 있지만, 저는 이 구조를 좋아합니다. 우리는 새로 만든 컴포넌트에 템플릿 블록을 추가할 것입니다. 오, 마이크, about 컴포넌트처럼요. 저는 manage 컴포넌트에 더미 콘텐츠를 추가하고 싶지 않습니다. 저는 이 컴포넌트에 정적 템플릿을 제공했습니다. 여러분은 managed HTML 파일을 열어 그것을 찾을 수 있습니다. 이 파일은 우리가 이전 섹션에서 다운로드한 에셋들과 함께 제공된 템플릿 중 하나입니다. 저는 가독성을 높이기 위해 일부 코드를 접을 것입니다. 우리가 복사해야 할 섹션은 container main이라는 클래스를 가진 section 요소입니다. 그것 위에는 '주요 콘텐츠'라고 하는 주석이 있습니다. 우리는 이 태그 안의 모든 것을 복사할 것입니다. 그런 다음 우리는 그것을 Manage 컴포넌트의 템플릿에 붙여넣을 것입니다. 붙여넣은 후에는 코드를 포맷할 필요가 있을 수 있습니다. 그것은 큰 템플릿입니다. 위협적으로 느껴지지 않도록 하세요. 저는 강의가 진행됨에 따라 모든 섹션을 설명할 것입니다. 우리가 끝날 때, 그것은 완전히 기능적일 것입니다. Manage 컴포넌트는 준비되었습니다. 우리는 라우터 파일에서 이 컴포넌트를 사용하도록 루트를 업데이트해야 할 것입니다. 우리는 manage 컴포넌트를 가져올 것입니다. 가져온 후에는 component 속성을 manage 컴포넌트로 설정하세요. 우리는 완성되었습니다. 브라우저에서 애플리케이션을 테스트해 보세요. 여러분은 인증된 사용자에게만 그 가시성을 제한했기 때문에 manage 페이지로의 링크를 보지 못할 수도 있습니다. 여러분이 로그인하지 않았다면 지금 하세요. 로그인한 후에. 우리는 링크를 볼 것입니다. 그것을 클릭해보세요. 우리는 새로운 페이지로 리디렉션될 것입니다. 이것은 우리가 manage 페이지를 위해 사용할 UI입니다. 왼쪽에는 노래를 업로드하기 위한 Dropbox가 있습니다. 이 Dropbox는 업로드 과정을 시작할 것입니다. 업로드 과정 동안, 우리는 그들의 업로드 진행 상황을 보여주기 위해 진행 상태 바를 표시할 것입니다. 오른쪽에는 업로드된 노래 목록을 찾을 수 있습니다. 사용자는 그들의 노래를 편집하거나 삭제할 수 있는 옵션이 있습니다. 만약 그들이 노래를 추가했다면, 그 노래에 대한 관련 설정이 있는 양식이 나타날 것입니다. 그들은 제목과 장르를 변경할 수 있을 것입니다. 우리는 미래에 이 페이지를 기능적으로 만들 것입니다. 라우팅에 대해 논의하고 싶은 추가적인 주제들이 있지만, 우리가 그것에 도달하기 전에 말이죠.
요약
이 강의에서는 앱의 헤더 컴포넌트 파일에서 링크 추가 작업을 계속합니다. 우선, 홈페이지 링크를 수정하여 about 페이지 대신 홈페이지(/)로 이동하도록 변경합니다. 그런 다음, about 페이지를 활용하기 위해 새로운 링크를 추가합니다. 이어서 'Manage' 페이지로의 링크를 추가합니다. 이 Manage 페이지는 추후 음악 업로드와 관련된 기능을 다룰 예정이며, 인증된 사용자만 업로드와 노래 편집이 가능하도록 설정됩니다. Manage 페이지에 대한 링크는 인증된 사용자에게만 표시됩니다. 또한, Manage 페이지의 UI에 대한 설명과 함께 그것을 기능적으로 만드는 과정이 향후 강의에서 다루어질 예정입니다.
import { createRouter, createWebHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
import AboutView from '@/views/AboutView.vue'
import ManageView from '@/views/ManageView.vue'
const routes: RouteRecordRaw[] = [
{
path: '/',
component: HomeView
},
{
path: '/about',
component: AboutView
},
{
path: '/manage',
component: ManageView
}
]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes
})
export default router
<script setup lang="ts"></script>
<template>
<!-- Main Content -->
<section class="container mx-auto mt-6">
<div class="md:grid md:grid-cols-3 md:gap-4">
<div class="col-span-1">
<div class="bg-white rounded border border-gray-200 relative flex flex-col">
<div class="px-6 pt-6 pb-5 font-bold border-b border-gray-200">
<span class="card-title">Upload</span>
<i class="fas fa-upload float-right text-green-400 text-2xl"></i>
</div>
<div class="p-6">
<!-- Upload Dropbox -->
<div
class="w-full px-10 py-20 rounded text-center cursor-pointer border border-dashed border-gray-400 text-gray-400 transition duration-500 hover:text-white hover:bg-green-400 hover:border-green-400 hover:border-solid"
>
<h5>Drop your files here</h5>
</div>
<hr class="my-6" />
<!-- Progess Bars -->
<div class="mb-4">
<!-- File Name -->
<div class="font-bold text-sm">Just another song.mp3</div>
<div class="flex h-4 overflow-hidden bg-gray-200 rounded">
<!-- Inner Progress Bar -->
<div class="transition-all progress-bar bg-blue-400" style="width: 75%"></div>
</div>
</div>
<div class="mb-4">
<div class="font-bold text-sm">Just another song.mp3</div>
<div class="flex h-4 overflow-hidden bg-gray-200 rounded">
<div class="transition-all progress-bar bg-blue-400" style="width: 35%"></div>
</div>
</div>
<div class="mb-4">
<div class="font-bold text-sm">Just another song.mp3</div>
<div class="flex h-4 overflow-hidden bg-gray-200 rounded">
<div class="transition-all progress-bar bg-blue-400" style="width: 55%"></div>
</div>
</div>
</div>
</div>
</div>
<div class="col-span-2">
<div class="bg-white rounded border border-gray-200 relative flex flex-col">
<div class="px-6 pt-6 pb-5 font-bold border-b border-gray-200">
<span class="card-title">My Songs</span>
<i class="fa fa-compact-disc float-right text-green-400 text-2xl"></i>
</div>
<div class="p-6">
<!-- Composition Items -->
<div class="border border-gray-200 p-3 mb-4 rounded">
<div>
<h4 class="inline-block text-2xl font-bold">Song Name</h4>
<button class="ml-1 py-1 px-2 text-sm rounded text-white bg-red-600 float-right">
<i class="fa fa-times"></i>
</button>
<button class="ml-1 py-1 px-2 text-sm rounded text-white bg-blue-600 float-right">
<i class="fa fa-pencil-alt"></i>
</button>
</div>
<div>
<form>
<div class="mb-3">
<label class="inline-block mb-2">Song Title</label>
<input
type="text"
class="block w-full py-1.5 px-3 text-gray-800 border border-gray-300 transition duration-500 focus:outline-none focus:border-black rounded"
placeholder="Enter Song Title"
/>
</div>
<div class="mb-3">
<label class="inline-block mb-2">Genre</label>
<input
type="text"
class="block w-full py-1.5 px-3 text-gray-800 border border-gray-300 transition duration-500 focus:outline-none focus:border-black rounded"
placeholder="Enter Genre"
/>
</div>
<button type="submit" class="py-1.5 px-3 rounded text-white bg-green-600">
Submit
</button>
<button type="button" class="py-1.5 px-3 rounded text-white bg-gray-600">
Go Back
</button>
</form>
</div>
</div>
<div class="border border-gray-200 p-3 mb-4 rounded">
<div>
<h4 class="inline-block text-2xl font-bold">Song Name</h4>
<button class="ml-1 py-1 px-2 text-sm rounded text-white bg-red-600 float-right">
<i class="fa fa-times"></i>
</button>
<button class="ml-1 py-1 px-2 text-sm rounded text-white bg-blue-600 float-right">
<i class="fa fa-pencil-alt"></i>
</button>
</div>
</div>
<div class="border border-gray-200 p-3 mb-4 rounded">
<div>
<h4 class="inline-block text-2xl font-bold">Song Name</h4>
<button class="ml-1 py-1 px-2 text-sm rounded text-white bg-red-600 float-right">
<i class="fa fa-times"></i>
</button>
<button class="ml-1 py-1 px-2 text-sm rounded text-white bg-blue-600 float-right">
<i class="fa fa-pencil-alt"></i>
</button>
</div>
</div>
<div class="border border-gray-200 p-3 mb-4 rounded">
<div>
<h4 class="inline-block text-2xl font-bold">Song Name</h4>
<button class="ml-1 py-1 px-2 text-sm rounded text-white bg-red-600 float-right">
<i class="fa fa-times"></i>
</button>
<button class="ml-1 py-1 px-2 text-sm rounded text-white bg-blue-600 float-right">
<i class="fa fa-pencil-alt"></i>
</button>
</div>
</div>
<div class="border border-gray-200 p-3 mb-4 rounded">
<div>
<h4 class="inline-block text-2xl font-bold">Song Name</h4>
<button class="ml-1 py-1 px-2 text-sm rounded text-white bg-red-600 float-right">
<i class="fa fa-times"></i>
</button>
<button class="ml-1 py-1 px-2 text-sm rounded text-white bg-blue-600 float-right">
<i class="fa fa-pencil-alt"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
<style scoped></style>
<script setup lang="ts">
import useModal from '@/stores/modal'
import useUser from '@/stores/user'
import { storeToRefs } from 'pinia'
const userStore = useUser()
const { signOut } = userStore
const { userLoggedIn } = storeToRefs(userStore)
const modalStore = useModal()
const { isOpen } = storeToRefs(modalStore)
const toggleAuthModal = () => {
isOpen.value = !isOpen.value
console.log(isOpen.value)
}
</script>
<template>
<!-- Header -->
<header id="header" class="bg-gray-700">
<nav class="container mx-auto flex justify-start items-center py-5 px-4">
<!-- App Name -->
<RouterLink class="text-white font-bold uppercase text-2xl mr-4" to="/"> Music </RouterLink>
<div class="flex flex-grow items-center">
<!-- Primary Navigation -->
<ul class="flex flex-row mt-1">
<li>
<RouterLink class="px-2 text-white" to="/about">About</RouterLink>
</li>
<!-- Navigation Links -->
<li v-if="!userLoggedIn">
<a class="px-2 text-white" href="#" @click.prevent="toggleAuthModal">
Login / Register
</a>
</li>
<template v-else>
<li>
<RouterLink class="px-2 text-white" to="/manage">Manage</RouterLink>
</li>
<li>
<a class="px-2 text-white" href="#" @click.prevent="signOut">Logout</a>
</li>
</template>
</ul>
</div>
</nav>
</header>
</template>
<style scoped></style>