mirror of
https://github.com/Xevion/the-office.git
synced 2026-01-31 06:26:18 -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 { ref } from 'vue';
|
||||
import logoSrc from '@/assets/logo.svg';
|
||||
import SearchBar from '@/components/layout/SearchBar.vue';
|
||||
|
||||
const sidebarOpen = ref(false);
|
||||
|
||||
@@ -62,28 +63,7 @@ const headings = [
|
||||
|
||||
<!-- Search bar -->
|
||||
<div class="hidden items-center md:flex">
|
||||
<div class="relative">
|
||||
<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>
|
||||
<SearchBar />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
@@ -103,12 +83,7 @@ const headings = [
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="col-span-8 lg:ml-0">
|
||||
<div class="p-6">
|
||||
<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>
|
||||
<RouterView />
|
||||
</main>
|
||||
</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,
|
||||
},
|
||||
{
|
||||
path: '/:season/',
|
||||
path: '/season/:season',
|
||||
name: 'Season',
|
||||
component: Season,
|
||||
},
|
||||
{
|
||||
path: '/:season/:episode',
|
||||
path: '/episode/:episode',
|
||||
name: '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>
|
||||
<div>
|
||||
<BBreadcrumb v-if="ready" :items="breadcrumbs" />
|
||||
<BCard v-else class="breadcrumb-skeleton mb-3">
|
||||
<div class="h-full w-full p-4">
|
||||
<Breadcrumb :items="breadcrumbs" />
|
||||
<!-- <BCard v-else class="breadcrumb-skeleton mb-3">
|
||||
<Skeleton style="width: 40%" />
|
||||
</BCard>
|
||||
</BCard> -->
|
||||
<BCard class="mb-4">
|
||||
<template v-if="ready">
|
||||
<h3 class="card-title">"{{ episode.title }}"</h3>
|
||||
@@ -50,96 +163,3 @@
|
||||
line-height: 12px;
|
||||
}
|
||||
</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