Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TV Content Page Updates #148

Merged
merged 22 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1536cec
wip
bryantgillespie Mar 21, 2024
f944c13
Merge branch 'main' into tv-me-data-fetching
bryantgillespie Mar 21, 2024
9b6e3a2
Update async data call in all.vue
bryantgillespie Mar 21, 2024
94dd27a
Remove unused imports in tv.ts
bryantgillespie Mar 21, 2024
cdd67f0
Update TV episode component to use TV URL for image source and format…
bryantgillespie Mar 21, 2024
7e711bf
Add formatTvDate function to utils/dates.ts
bryantgillespie Mar 21, 2024
b0e4c97
Refactor formatDate function to use formatTvDate
bryantgillespie Mar 21, 2024
ada1bb9
Remove unused import in index.vue
bryantgillespie Mar 21, 2024
850669e
cleanup
bryantgillespie Mar 21, 2024
eb63715
Add schema.org markup for video metadata
bryantgillespie Mar 22, 2024
fc07dcf
Add website.svg social icon
bryantgillespie Mar 26, 2024
929372f
Add provider option to DirectusImageProps and update Nuxt Image confi…
bryantgillespie Mar 26, 2024
a290e28
Add TVByline and TVReactions components
bryantgillespie Mar 26, 2024
0fe05f2
Add visitor ID tracking for TV pages
bryantgillespie Mar 26, 2024
c79bb93
fix popper hydration issues
bryantgillespie Mar 26, 2024
5a8bba7
update TVShow to accept URL
bryantgillespie Mar 26, 2024
845943b
Add recommendations section to TV episode page
bryantgillespie Mar 26, 2024
d306514
Merge branch 'main' into tv-me-content
bryantgillespie Mar 27, 2024
f75d179
Merge branch 'main' into tv-me-content
bryantgillespie Mar 27, 2024
6e31ff6
fix css warnings
bryantgillespie Mar 29, 2024
ca60244
fix padding for transcript
bryantgillespie Mar 29, 2024
1297123
add divider between content and meta
bryantgillespie Mar 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/svg/social/website.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 5 additions & 2 deletions components/Base/DirectusImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ export interface DirectusImageProps {

width?: number;
height?: number;
provider?: string;
}

defineProps<DirectusImageProps>();
withDefaults(defineProps<DirectusImageProps>(), {
provider: 'directus',
});
</script>

<template>
<NuxtImg :src="uuid" :alt="alt" :width="width" :height="height" format="auto" loading="lazy" />
<NuxtImg :src="uuid" :alt="alt" :width="width" :height="height" format="auto" loading="lazy" :provider />
</template>
2 changes: 1 addition & 1 deletion components/Block/Showcase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ loop();
.block-showcase {
@container (width > 50rem) {
display: grid;
align-items: start;
align-items: flex-start;
grid-template-columns: repeat(v-bind(sections), 1fr);
gap: var(--space-8);
}
Expand Down
98 changes: 98 additions & 0 deletions components/Tv/TVByline.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script setup lang="ts">
interface BaseBylineProps {
name?: string;
title?: string;
image?: string;
links?: [
{
service: string;
url: string;
},
];
}

defineProps<BaseBylineProps>();
</script>

<template>
<address rel="author" class="base-byline">
<BaseDirectusImage
v-if="image"
:width="44"
:height="44"
class="avatar"
:uuid="image"
:alt="name ?? ''"
provider="directusTv"
/>

<div>
<p v-if="name" class="name">{{ name }}</p>
<p v-if="title" class="title">{{ title }}</p>
<div v-if="links" class="share-icons">
<template v-for="{ service, url } in links" :key="service">
<NuxtLink :href="url" target="_blank">
<img :src="dynamicAsset(`/svg/social/${service}.svg`)" :alt="service" />
</NuxtLink>
</template>
</div>
</div>
</address>
</template>

<style scoped lang="scss">
.base-byline {
--color: var(--foreground);
--title-color: var(--gray-400);
--text-shadow: none;

color: var(--color);
display: flex;
gap: var(--space-2);
font-style: normal;
align-items: flex-start;

.avatar {
border-radius: var(--rounded-full);
inline-size: var(--space-11);
block-size: var(--space-11);
object-fit: cover;
background: var(--gray-100);
}

div {
text-shadow: var(--text-shadow);
}

.name,
.title {
margin: 0;
}

.title {
color: var(--title-color);
font-size: var(--font-size-sm);
line-height: var(--line-height-sm);
text-wrap: balance;
}

.share-icons {
display: flex;
align-items: center;
gap: var(--space-5);

img {
margin-block-start: var(--space-1);
width: var(--space-6);
height: auto;
filter: brightness(1);
transition: filter var(--duration-150) var(--ease-out);

&:hover {
transition: none;
filter: brightness(50);
}
}
}
}
</style>
239 changes: 239 additions & 0 deletions components/Tv/TVReactions.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
<script setup>
import { createItem, updateItem } from '@directus/sdk';

const { $directusTv } = useNuxtApp();
const ariaId = useId();

const props = defineProps({
episodeId: {
type: String,
required: true,
},
});

const visitorId = useCookie('visitor_id');

const loading = ref(false);
const error = ref(null);
const success = ref(false);

const reaction = reactive({
comments: '',
});

const textarea = ref(null);

const isOpen = ref(false);

const ratingMessages = {
dislike: 'Woof! 🤦‍♂️ How can we do better?',
like: 'Nice! 👍 Anything we can improve upon?',
love: `Awesome! The whole team is rejoicing in celebration! 🥳🎉🎊 Anything you'd like to say to them?`,
};

async function submitReaction(type) {
isOpen.value = true;
loading.value = true;

if (type) {
reaction.type = type;
}

try {
if (reaction.id) {
const response = await $directusTv.request(
updateItem('tv_episode_reactions', reaction.id, {
episode: props.episodeId,
type: reaction.type,
comments: reaction.comments,
visitor_id: visitorId.value,
}),
);

if (response.comments) {
success.value = true;

await setTimeout(() => {
isOpen.value = false;
}, 2000);
}
} else {
const data = await $directusTv.request(
createItem('tv_episode_reactions', {
episode: props.episodeId,
type: reaction.type,
comments: reaction.comments,
visitor_id: visitorId.value,
}),
);

reaction.id = data.id;
}
} catch (e) {
error.value = e;
} finally {
loading.value = false;
}
}

watch(isOpen, (value) => {
if (value) {
setTimeout(() => {
textarea.value.focus();
}, 100);
}
});

onKeyStroke('Escape', () => {
isOpen.value = false;
});
</script>
<template>
<div>
<VDropdown :aria-id class="reactions" :triggers="[]" :shown="isOpen" :auto-hide="false">
<button
v-tooltip="`I do not like this`"
class="feedback-button"
:aria-pressed="reaction.type === 'dislike'"
@click="() => submitReaction('dislike')"
>
<BaseIcon name="thumb_down" />
</button>
<button
v-tooltip="'I like this'"
class="feedback-button"
:aria-pressed="reaction.type === 'like'"
@click="() => submitReaction('like')"
>
<BaseIcon name="thumb_up" />
</button>
<button
v-tooltip="'I freaking love this'"
:aria-pressed="reaction.type === 'love'"
class="feedback-button"
@click="() => submitReaction('love')"
>
<BaseIcon name="favorite" />
</button>
<template #popper>
<ThemeProvider variant="dark">
<div class="popover">
<template v-if="!success">
<p>{{ ratingMessages[reaction.type] }}</p>
<textarea ref="textarea" v-model="reaction.comments" class="input" placeholder="Give us your feedback" />
<BaseButton
type="button"
:loading="loading"
:disabled="loading"
color="primary"
label="Send Your Feedback"
@click="submitReaction(reaction.type)"
/>
</template>
<template v-else-if="error">
<p>Whoops! There was an error submitting your feedback.</p>
</template>
<template v-else-if="success">
<p>Thank you for your feedback!</p>
</template>
<button class="close-button" @click="() => (isOpen = false)">
<BaseIcon name="close" />
</button>
</div>
</ThemeProvider>
</template>
</VDropdown>
</div>
</template>

<style lang="scss" scoped>
.reactions {
display: flex;
align-content: center;
border-radius: var(--rounded-full);
background: var(--gray-100);
padding: var(--space-1);
gap: var(--space-1);
}

.feedback-button {
transition: background-color 0.2s;
background: none;
border: none;
cursor: pointer;
padding: var(--space-2);
&:hover {
background: var(--gray-200);
}
border-radius: var(--rounded-full);
&[aria-pressed='true'] {
background: var(--primary-500);
color: var(--white);
}
}

.popover {
position: relative;
width: 350px;
padding: var(--space-5);
background-color: var(--gray-100);
border-radius: var(--rounded-xl);
border: 2px solid var(--gray-200);
display: flex;
flex-direction: column;
gap: var(--space-2);
box-shadow: var(--shadow-lg);

button {
width: auto;
}

.close-button {
position: absolute;
top: var(--space-2);
right: var(--space-2);
background: none;
border: none;
cursor: pointer;
padding: var(--space-2);
border-radius: var(--rounded-full);
&:hover {
background: var(--gray-200);
}
}
}

.input {
color: var(--gray-900);
width: 100%;
height: 100px;
border-radius: 4px;
padding: 0.375rem 0.75rem;
background-color: var(--gray-50);
border: 1px solid var(--gray-200);
&:focus {
border-color: var(--primary);
outline: none;
box-shadow: 0px 0px var(--space-1) 0px var(--primary-100);
}
}
</style>

<style lang="css">
.v-popper--theme-dropdown {
.v-popper__inner {
background-color: transparent !important;
border: none !important;
border-radius: 6px;
}

.v-popper__arrow-container {
.v-popper__arrow-outer {
border-color: #334155;
}
.v-popper__arrow-inner {
border-color: #334155;
}
}
}
</style>
3 changes: 2 additions & 1 deletion components/Tv/TVShow.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<NuxtLink :to="`/tv/${slug}`" class="show">
<NuxtLink :to="url ? url : `/tv/${slug}`" class="show">
<div class="tile" :style="`background-image: url(${directusUrl}/assets/${tile}?width=600)`">
<span v-if="overlay">{{ overlay }}</span>
</div>
Expand All @@ -16,6 +16,7 @@ const {
const directusUrl = process.env.DIRECTUS_TV_URL || tvUrl;

defineProps({
url: String,
slug: String,
tile: String,
title: String,
Expand Down
9 changes: 9 additions & 0 deletions layouts/tv.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
useHead({
bodyAttrs: { class: 'tv' },
});

// Generate a unique visitor ID for each user of TV pages to track reactions
const visitorId = useCookie('visitor_id');

if (!visitorId.value) {
const id = useId();

visitorId.value = id;
}
</script>

<template>
Expand Down
Loading