improved broken image handling and cleaned up modal formatting
This commit is contained in:
parent
bb6a9685d6
commit
4e6331327c
8 changed files with 116 additions and 42 deletions
48
src/assets/img/poster-placeholder.svg
Normal file
48
src/assets/img/poster-placeholder.svg
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
viewBox="1413.5 192.80002 108.59998 149.10001"
|
||||||
|
width="108.59998"
|
||||||
|
height="149.10001"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="poster-placeholder.svg"
|
||||||
|
inkscape:export-filename="poster-placeholder2.svg"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:export-bgcolor="#ffffffff">
|
||||||
|
<inkscape:page
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="108.59998"
|
||||||
|
height="149.10001"
|
||||||
|
id="page2"
|
||||||
|
margin="0"
|
||||||
|
bleed="0" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<rect
|
||||||
|
style="fill:#5c5b79;fill-opacity:1"
|
||||||
|
id="rect1"
|
||||||
|
width="108.28388"
|
||||||
|
height="148.72725"
|
||||||
|
x="1413.6864"
|
||||||
|
y="193.17278" />
|
||||||
|
<path
|
||||||
|
fill="#cccccc"
|
||||||
|
d="m 1413.5,242.5 c 0,16.6 0,33.1 0,49.7 36.2,49.7 72.4,-49.7 108.6,0 0,-16.6 0,-33.1 0,-49.7 -36.2,-49.7 -72.4,49.7 -108.6,0 z m 8.7,56.7 c -1.6,-1.3 -3.3,-2.8 -4.9,-4.6 0,-1.6 0,-3.3 0,-4.9 1.6,1.8 3.3,3.3 4.9,4.6 0,1.7 0,3.3 0,4.9 z m 0,-39.8 c -1.6,-1.3 -3.3,-2.8 -4.9,-4.6 0,-1.6 0,-3.3 0,-4.9 1.6,1.8 3.3,3.3 4.9,4.6 0,1.6 0,3.3 0,4.9 z m 9.6,44.4 c -1.6,-0.4 -3.3,-0.9 -4.9,-1.7 0,-1.6 0,-3.3 0,-4.9 1.6,0.8 3.3,1.4 4.9,1.7 0,1.7 0,3.3 0,4.9 z m 0,-39.8 c -1.6,-0.4 -3.3,-0.9 -4.9,-1.7 0,-1.6 0,-3.3 0,-4.9 1.6,0.8 3.3,1.4 4.9,1.7 0,1.7 0,3.3 0,4.9 z m 9.6,39.8 c -1.6,0.3 -3.3,0.5 -4.9,0.5 0,-1.6 0,-3.3 0,-4.9 1.6,0 3.3,-0.2 4.9,-0.5 0,1.7 0,3.3 0,4.9 z m 0,-39.8 c -1.6,0.3 -3.3,0.5 -4.9,0.5 0,-1.6 0,-3.3 0,-4.9 1.6,0 3.3,-0.2 4.9,-0.5 0,1.6 0,3.3 0,4.9 z m 9.6,36.4 c -1.6,0.8 -3.3,1.5 -4.9,2.1 0,-1.6 0,-3.3 0,-4.9 1.6,-0.6 3.3,-1.3 4.9,-2.1 0,1.7 0,3.3 0,4.9 z m 0,-39.8 c -1.6,0.8 -3.3,1.5 -4.9,2.1 0,-1.6 0,-3.3 0,-4.9 1.6,-0.6 3.3,-1.3 4.9,-2.1 0,1.6 0,3.3 0,4.9 z m 9.5,34.3 c -1.6,1.1 -3.3,2.1 -4.9,3 0,-1.6 0,-3.3 0,-4.9 1.6,-1 3.3,-2 4.9,-3 0,1.6 0,3.2 0,4.9 z m 0,-39.8 c -1.6,1.1 -3.3,2.1 -4.9,3 0,-1.6 0,-3.3 0,-4.9 1.6,-1 3.3,-2 4.9,-3 0,1.6 0,3.2 0,4.9 z m 9.6,33.3 c -1.6,1.1 -3.3,2.3 -4.9,3.4 0,-1.6 0,-3.3 0,-4.9 1.6,-1.1 3.3,-2.2 4.9,-3.4 0,1.6 0,3.2 0,4.9 z m 0,-39.8 c -1.6,1.1 -3.3,2.3 -4.9,3.4 0,-1.6 0,-3.3 0,-4.9 1.6,-1.1 3.3,-2.2 4.9,-3.4 0,1.6 0,3.2 0,4.9 z m 9.6,33.6 c -1.6,1 -3.3,2 -4.9,3.1 0,-1.6 0,-3.3 0,-4.9 1.6,-1.1 3.3,-2.1 4.9,-3.1 0,1.6 0,3.3 0,4.9 z m 0,-39.8 c -1.6,1 -3.3,2 -4.9,3.1 0,-1.6 0,-3.3 0,-4.9 1.6,-1.1 3.3,-2.1 4.9,-3.1 0,1.6 0,3.2 0,4.9 z m 9.6,35.1 c -1.6,0.6 -3.3,1.3 -4.9,2.1 0,-1.6 0,-3.3 0,-4.9 1.6,-0.8 3.3,-1.5 4.9,-2.1 0,1.7 0,3.3 0,4.9 z m 0,-39.8 c -1.6,0.6 -3.3,1.3 -4.9,2.1 0,-1.6 0,-3.3 0,-4.9 1.6,-0.8 3.3,-1.5 4.9,-2.1 0,1.7 0,3.3 0,4.9 z m 9.6,37.9 c -1.6,0 -3.3,0.2 -4.9,0.6 0,-1.6 0,-3.3 0,-4.9 1.6,-0.3 3.3,-0.5 4.9,-0.6 0,1.7 0,3.3 0,4.9 z m 0,-39.8 c -1.6,0 -3.3,0.2 -4.9,0.6 0,-1.6 0,-3.3 0,-4.9 1.6,-0.3 3.3,-0.5 4.9,-0.6 0,1.6 0,3.3 0,4.9 z m 14.2,0 c 1.6,1.2 3.3,2.7 4.9,4.5 0,1.6 0,3.3 0,4.9 -1.6,-1.8 -3.3,-3.2 -4.9,-4.5 0,-1.6 0,-3.2 0,-4.9 z m 0,39.8 c 1.6,1.2 3.3,2.7 4.9,4.5 0,1.6 0,3.3 0,4.9 -1.6,-1.8 -3.3,-3.2 -4.9,-4.5 0,-1.6 0,-3.2 0,-4.9 z m -9.6,-44.2 c 1.6,0.3 3.3,0.9 4.9,1.6 0,1.6 0,3.3 0,4.9 -1.6,-0.8 -3.3,-1.3 -4.9,-1.6 0,-1.7 0,-3.3 0,-4.9 z m 0,39.8 c 1.6,0.3 3.3,0.9 4.9,1.6 0,1.6 0,3.3 0,4.9 -1.6,-0.8 -3.3,-1.3 -4.9,-1.6 0,-1.7 0,-3.3 0,-4.9 z"
|
||||||
|
id="path1" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.6 KiB |
|
@ -1,12 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-show="visible" id="movie-modal" class="movie-modal movie-card p-5">
|
<div v-show="visible" id="movie-modal" class="movie-modal movie-card">
|
||||||
<span
|
<div class="max-w-4xl mx-auto flex flex-col px-2 sm:px-0">
|
||||||
class="hover-pointer font-bold w-full block text-right sm:pr-5 pb-3 pt-5"
|
<span
|
||||||
@click="toggleModal()"
|
class="hover-pointer font-bold self-end pr-1 sm:pr-5 pt-5 pb-5 sm:pb-0"
|
||||||
>
|
@click="toggleModal()"
|
||||||
X
|
>
|
||||||
</span>
|
<span class="bg-red-600 p-2 rounded">X</span>
|
||||||
<slot class=""></slot>
|
</span>
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
36
src/components/MoviePoster.vue
Normal file
36
src/components/MoviePoster.vue
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import placeholderPoster from "assets/img/poster-placeholder.svg";
|
||||||
|
|
||||||
|
const imgRef = ref<HTMLImageElement | null>(null);
|
||||||
|
const props = defineProps(["image"]);
|
||||||
|
|
||||||
|
const handleImageError = function (event: Event) {
|
||||||
|
(event.target as HTMLImageElement).classList.remove("lazyload");
|
||||||
|
(event.target as HTMLImageElement).classList.add("object-cover");
|
||||||
|
(event.target as HTMLImageElement).src = placeholderPoster;
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.image,
|
||||||
|
(newImage) => {
|
||||||
|
if (imgRef.value && newImage) {
|
||||||
|
imgRef.value.classList.add("lazyload");
|
||||||
|
imgRef.value.setAttribute("data-src", newImage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="aspect-[2/3] w-full text-blue-300">
|
||||||
|
<img
|
||||||
|
ref="imgRef"
|
||||||
|
:data-src="props.image"
|
||||||
|
alt="Movie Details"
|
||||||
|
class="lazyload hover-pointer w-full h-full"
|
||||||
|
@error="handleImageError"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
|
@ -8,12 +8,7 @@
|
||||||
</form>
|
</form>
|
||||||
<ul class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 gap-4">
|
<ul class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 gap-4">
|
||||||
<li v-for="movie in movies" class="p-1 movie-card">
|
<li v-for="movie in movies" class="p-1 movie-card">
|
||||||
<img
|
<MoviePoster :image="movie.poster" @click="showModal(movie)" />
|
||||||
:src="movie.poster"
|
|
||||||
alt="movie poster"
|
|
||||||
class="neon-border hover-pointer"
|
|
||||||
@click="showModal(movie)"
|
|
||||||
/>
|
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<h5 class="text-center">{{ movie.title }} ({{ movie.year }})</h5>
|
<h5 class="text-center">{{ movie.title }} ({{ movie.year }})</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="props.movie != null" class="sm:m-5 p-10 movie-card neon-border">
|
<div v-if="props.movie != null" class="sm:m-5 p-10 movie-card neon-border">
|
||||||
<div>
|
<div>
|
||||||
<h2 id="modal-title" class="row pb-3">
|
<h2 id="modal-title" class="row pb-10">
|
||||||
{{ movie.title }} ({{ movie.year }})
|
{{ movie.title }} ({{ movie.year }})
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="grid sm:grid-cols-2">
|
<div class="grid sm:grid-cols-2 gap-5">
|
||||||
<!-- MODAL POSTER -->
|
<!-- MODAL POSTER -->
|
||||||
<div class="text-end">
|
<MoviePoster
|
||||||
<img
|
:image="movie.poster"
|
||||||
id="modal-poster"
|
class="max-h-80 max-w-72 sm:max-h-none sm:max-w-none mx-auto sm:mx-none"
|
||||||
:src="movie.poster"
|
/>
|
||||||
alt="poster"
|
|
||||||
class="pt-5"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pt-5">
|
<div class="mx-auto sm:mx-none">
|
||||||
<label class="" for="list-picker">Add To List</label><br />
|
<label class="" for="list-picker">Add To List</label><br />
|
||||||
<select id="list-picker" v-model="list_id" class="p-1 text-black">
|
<select id="list-picker" v-model="list_id" class="p-1 text-black">
|
||||||
<option v-for="list in lists" :value="list.id">
|
<option v-for="list in lists" :value="list.id">
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
<div class="sm:m-5 p-10 movie-card neon-border">
|
<div class="sm:m-5 p-10 movie-card neon-border">
|
||||||
<div>
|
<div>
|
||||||
<LoadingIcon v-if="updating" />
|
<LoadingIcon v-if="updating" />
|
||||||
<h2 class="text-xl pb-3 text-center sm:text-left">
|
<h2 class="text-xl pb-10 text-center sm:text-left">
|
||||||
{{ movie.title }} ({{ movie.year }})
|
{{ movie.title }} ({{ movie.year }})
|
||||||
</h2>
|
</h2>
|
||||||
<div class="sm:inline-flex sm:space-x-5">
|
<div class="sm:inline-flex sm:space-x-5">
|
||||||
<img
|
<MoviePoster
|
||||||
:src="movie.poster"
|
:image="movie.poster"
|
||||||
alt="movie poster"
|
class="max-h-80 max-w-72 mx-auto sm:mx-none"
|
||||||
class="mx-auto sm:mx-0 neon-border"
|
|
||||||
/>
|
/>
|
||||||
<div class="pt-5 sm:pt-0">
|
<div class="pt-5 sm:pt-0">
|
||||||
<p>{{ movie.plot }}</p>
|
<p>{{ movie.plot }}</p>
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container mx-auto">
|
<div class="container mx-auto">
|
||||||
<Navbar/>
|
<Navbar />
|
||||||
<NuxtPage/>
|
<NuxtPage class="mb-32" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "default",
|
name: "default",
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -41,16 +41,15 @@
|
||||||
<li
|
<li
|
||||||
v-for="movie in filtered_movies"
|
v-for="movie in filtered_movies"
|
||||||
:key="movie.poster"
|
:key="movie.poster"
|
||||||
class="rounded movie-card neon-border"
|
class="rounded movie-card neon-border flex flex-col overflow-hidden"
|
||||||
>
|
>
|
||||||
<!-- POSTER -->
|
<!-- POSTER -->
|
||||||
<img
|
<MoviePoster
|
||||||
:data-src="movie.poster"
|
:image="movie.poster"
|
||||||
alt="movie poster"
|
class="flex-shrink-0"
|
||||||
class="lazyload p-3 movie-poster hover-pointer mx-auto"
|
|
||||||
@click="showModal(movie)"
|
@click="showModal(movie)"
|
||||||
/>
|
/>
|
||||||
<div class="p-5 flex flex-col">
|
<div class="p-5 flex flex-col justify-between flex-1">
|
||||||
<!-- TITLE -->
|
<!-- TITLE -->
|
||||||
<span class="font-bold text-center mb-1">{{ movie.title }}</span>
|
<span class="font-bold text-center mb-1">{{ movie.title }}</span>
|
||||||
<span
|
<span
|
||||||
|
@ -74,6 +73,7 @@ import type { Movie } from "~/types/movie";
|
||||||
import Modal from "~/components/Modal.vue";
|
import Modal from "~/components/Modal.vue";
|
||||||
import { useCookie } from "#app";
|
import { useCookie } from "#app";
|
||||||
import { $fetch } from "ofetch";
|
import { $fetch } from "ofetch";
|
||||||
|
import MoviePoster from "~/components/MoviePoster.vue";
|
||||||
|
|
||||||
const list_id = ref(0);
|
const list_id = ref(0);
|
||||||
const list = defineModel<MovieList>("movie_list", { default: [] });
|
const list = defineModel<MovieList>("movie_list", { default: [] });
|
||||||
|
|
Loading…
Add table
Reference in a new issue