mirror of
https://github.com/Xevion/the-office.git
synced 2026-01-31 08:26:13 -06:00
feat: separate SearchBar in App.vue, start work on Episode view
This commit is contained in:
+3
-28
@@ -2,6 +2,7 @@
|
|||||||
import SeasonList from '@/components/layout/SeasonList.vue';
|
import SeasonList from '@/components/layout/SeasonList.vue';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import logoSrc from '@/assets/logo.svg';
|
import logoSrc from '@/assets/logo.svg';
|
||||||
|
import SearchBar from '@/components/layout/SearchBar.vue';
|
||||||
|
|
||||||
const sidebarOpen = ref(false);
|
const sidebarOpen = ref(false);
|
||||||
|
|
||||||
@@ -62,28 +63,7 @@ const headings = [
|
|||||||
|
|
||||||
<!-- Search bar -->
|
<!-- Search bar -->
|
||||||
<div class="hidden items-center md:flex">
|
<div class="hidden items-center md:flex">
|
||||||
<div class="relative">
|
<SearchBar />
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="Search..."
|
|
||||||
class="w-64 rounded-lg border border-gray-300 py-2 pr-4 pl-10 outline-none focus:border-transparent focus:ring-2 focus:ring-blue-500"
|
|
||||||
/>
|
|
||||||
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
|
||||||
<svg
|
|
||||||
class="h-5 w-5 text-gray-400"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -103,12 +83,7 @@ const headings = [
|
|||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<main class="col-span-8 lg:ml-0">
|
<main class="col-span-8 lg:ml-0">
|
||||||
<div class="p-6">
|
<RouterView />
|
||||||
<h2 class="mb-6 text-2xl text-gray-900">Welcome to The Office</h2>
|
|
||||||
<p class="text-gray-600">
|
|
||||||
This is your main content area. You can add your router-view or other components here.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { SearchIcon } from 'lucide-vue-next';
|
||||||
|
|
||||||
|
const searchQuery = ref('');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="relative">
|
||||||
|
<input
|
||||||
|
v-model="searchQuery"
|
||||||
|
type="text"
|
||||||
|
placeholder="Quotes, characters, episodes..."
|
||||||
|
class="w-72 rounded-lg border border-gray-400 py-2 pr-4 pl-10 outline-none focus:border-transparent focus:ring-2 focus:ring-blue-500"
|
||||||
|
/>
|
||||||
|
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
||||||
|
<SearchIcon class="size-5 text-gray-500" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
+2
-2
@@ -37,12 +37,12 @@ const router = createRouter({
|
|||||||
component: Character,
|
component: Character,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/:season/',
|
path: '/season/:season',
|
||||||
name: 'Season',
|
name: 'Season',
|
||||||
component: Season,
|
component: Season,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/:season/:episode',
|
path: '/episode/:episode',
|
||||||
name: 'Episode',
|
name: 'Episode',
|
||||||
component: Episode,
|
component: Episode,
|
||||||
},
|
},
|
||||||
|
|||||||
+117
-97
@@ -1,9 +1,122 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import QuoteList from '@/components/features/QuoteList.vue';
|
||||||
|
import CharacterBadges from '@/components/features/CharacterBadges.vue';
|
||||||
|
import Skeleton from '@/components/common/Skeleton.vue';
|
||||||
|
import Breadcrumb from '@/components/common/Breadcrumb.vue';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
// import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
// const route = useRoute();
|
||||||
|
|
||||||
|
const route = {
|
||||||
|
params: {
|
||||||
|
season: '1',
|
||||||
|
episode: '1',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const breadcrumbs = computed(() => {
|
||||||
|
return [
|
||||||
|
{ text: 'Home', to: { name: 'Home' } },
|
||||||
|
{ text: `Season ${route.params.season}`, to: { name: 'Season', season: route.params.season } },
|
||||||
|
{
|
||||||
|
text: `Episode ${route.params.episode}`,
|
||||||
|
to: { name: 'Episode', season: route.params.season, episode: route.params.episode },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
// export default defineComponent({
|
||||||
|
// name: 'EpisodeComponent',
|
||||||
|
|
||||||
|
// components: {
|
||||||
|
// QuoteList,
|
||||||
|
// CharacterBadges,
|
||||||
|
// Skeleton,
|
||||||
|
// BBreadcrumb,
|
||||||
|
// },
|
||||||
|
|
||||||
|
// computed: {
|
||||||
|
// episode() {
|
||||||
|
// return this.$store.getters.getEpisode(this.params.season, this.params.episode);
|
||||||
|
// },
|
||||||
|
// // Shorthand - literally useless, why does everything to have such long prefixes in dot notation
|
||||||
|
// params() {
|
||||||
|
// return this.$route.params;
|
||||||
|
// },
|
||||||
|
// ready() {
|
||||||
|
// return this.$store.getters.isFetched(this.params.season, this.params.episode);
|
||||||
|
// },
|
||||||
|
// breadcrumbs() {
|
||||||
|
// return [
|
||||||
|
// {
|
||||||
|
// text: 'Home',
|
||||||
|
// to: {
|
||||||
|
// name: 'Home',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// text: `Season ${this.$route.params.season}`,
|
||||||
|
// to: {
|
||||||
|
// name: 'Season',
|
||||||
|
// season: this.$route.params.season,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// text: `Episode ${this.$route.params.episode}`,
|
||||||
|
// to: {
|
||||||
|
// name: 'Episode',
|
||||||
|
// season: this.$route.params.season,
|
||||||
|
// episode: this.$route.params.episode,
|
||||||
|
// },
|
||||||
|
// active: true,
|
||||||
|
// },
|
||||||
|
// ];
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
|
||||||
|
// watch: {
|
||||||
|
// // When route changes, fetch data for current Episode route
|
||||||
|
// $route() {
|
||||||
|
// nextTick(() => {
|
||||||
|
// this.fetch();
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
|
||||||
|
// created() {
|
||||||
|
// // When page loads directly on this Episode initially, fetch data
|
||||||
|
// this.fetch();
|
||||||
|
// },
|
||||||
|
|
||||||
|
// methods: {
|
||||||
|
// async fetch() {
|
||||||
|
// // Fetch the episode, then scroll - already fetched episode should scroll immediately
|
||||||
|
// this.$store
|
||||||
|
// .dispatch(types.FETCH_EPISODE, { season: this.params.season, episode: this.params.episode })
|
||||||
|
// .then(() => {
|
||||||
|
// // Force update, as for some reason it doesn't update naturally. I hate it too.
|
||||||
|
// this.$forceUpdate();
|
||||||
|
|
||||||
|
// // Scroll down to quote
|
||||||
|
// if (this.$route.hash) {
|
||||||
|
// nextTick(() => {
|
||||||
|
// const section = document.getElementById(this.$route.hash.substring(1));
|
||||||
|
// this.$scrollTo(section, 500, { easing: 'ease-in' });
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="h-full w-full p-4">
|
||||||
<BBreadcrumb v-if="ready" :items="breadcrumbs" />
|
<Breadcrumb :items="breadcrumbs" />
|
||||||
<BCard v-else class="breadcrumb-skeleton mb-3">
|
<!-- <BCard v-else class="breadcrumb-skeleton mb-3">
|
||||||
<Skeleton style="width: 40%" />
|
<Skeleton style="width: 40%" />
|
||||||
</BCard>
|
</BCard> -->
|
||||||
<BCard class="mb-4">
|
<BCard class="mb-4">
|
||||||
<template v-if="ready">
|
<template v-if="ready">
|
||||||
<h3 class="card-title">"{{ episode.title }}"</h3>
|
<h3 class="card-title">"{{ episode.title }}"</h3>
|
||||||
@@ -50,96 +163,3 @@
|
|||||||
line-height: 12px;
|
line-height: 12px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, nextTick } from 'vue';
|
|
||||||
|
|
||||||
import QuoteList from '@/components/features/QuoteList.vue';
|
|
||||||
import CharacterBadges from '@/components/features/CharacterBadges.vue';
|
|
||||||
import Skeleton from '@/components/common/Skeleton.vue';
|
|
||||||
import { BBreadcrumb } from 'bootstrap-vue-next';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'EpisodeComponent',
|
|
||||||
|
|
||||||
components: {
|
|
||||||
QuoteList,
|
|
||||||
CharacterBadges,
|
|
||||||
Skeleton,
|
|
||||||
BBreadcrumb,
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
episode() {
|
|
||||||
return this.$store.getters.getEpisode(this.params.season, this.params.episode);
|
|
||||||
},
|
|
||||||
// Shorthand - literally useless, why does everything to have such long prefixes in dot notation
|
|
||||||
params() {
|
|
||||||
return this.$route.params;
|
|
||||||
},
|
|
||||||
ready() {
|
|
||||||
return this.$store.getters.isFetched(this.params.season, this.params.episode);
|
|
||||||
},
|
|
||||||
breadcrumbs() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
text: 'Home',
|
|
||||||
to: {
|
|
||||||
name: 'Home',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: `Season ${this.$route.params.season}`,
|
|
||||||
to: {
|
|
||||||
name: 'Season',
|
|
||||||
season: this.$route.params.season,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: `Episode ${this.$route.params.episode}`,
|
|
||||||
to: {
|
|
||||||
name: 'Episode',
|
|
||||||
season: this.$route.params.season,
|
|
||||||
episode: this.$route.params.episode,
|
|
||||||
},
|
|
||||||
active: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
// When route changes, fetch data for current Episode route
|
|
||||||
$route() {
|
|
||||||
nextTick(() => {
|
|
||||||
this.fetch();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
// When page loads directly on this Episode initially, fetch data
|
|
||||||
this.fetch();
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
async fetch() {
|
|
||||||
// Fetch the episode, then scroll - already fetched episode should scroll immediately
|
|
||||||
this.$store
|
|
||||||
.dispatch(types.FETCH_EPISODE, { season: this.params.season, episode: this.params.episode })
|
|
||||||
.then(() => {
|
|
||||||
// Force update, as for some reason it doesn't update naturally. I hate it too.
|
|
||||||
this.$forceUpdate();
|
|
||||||
|
|
||||||
// Scroll down to quote
|
|
||||||
if (this.$route.hash) {
|
|
||||||
nextTick(() => {
|
|
||||||
const section = document.getElementById(this.$route.hash.substring(1));
|
|
||||||
this.$scrollTo(section, 500, { easing: 'ease-in' });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user