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

Homepage Refresh #173

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
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
13 changes: 13 additions & 0 deletions assets/svg/placeholder-avatar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/svg/star.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions components/Base/Block.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ const components: Record<BlockType, ReturnType<typeof resolveComponent>> = {
block_card_group_dynamic: resolveComponent('BlockCardGroupDynamic'),
block_card_group: resolveComponent('BlockCardGroup'),
block_card: resolveComponent('BlockCard'),
block_carousel: resolveComponent('BlockCarousel'),
block_carousel_cards: resolveComponent('BlockCarouselCard'),
block_masonry_grid: resolveComponent('BlockMasonryGrid'),
block_masonry_grid_card: resolveComponent('BlockMasonryGridCard'),
block_wall_of_love: resolveComponent('BlockWallOfLove'),
block_code: resolveComponent('BlockCode'),
block_columns: resolveComponent('BlockColumns'),
block_cta: resolveComponent('BlockCta'),
Expand Down
44 changes: 43 additions & 1 deletion components/Base/Button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface BaseButtonProps {
href?: string;
target?: '_blank' | '_self' | '_parent' | '_top';
outline?: boolean;
ghost?: boolean;
block?: boolean;
disabled?: boolean;
}
Expand Down Expand Up @@ -60,7 +61,7 @@ const { theme } = useTheme();
`size-${size}`,
`color-${color}`,
`theme-${theme}`,
{ 'icon-only': isIconOnly, outline, 'size-block': block },
{ 'icon-only': isIconOnly, outline, ghost, 'size-block': block },
{
disabled,
},
Expand Down Expand Up @@ -148,6 +149,15 @@ const { theme } = useTheme();
--background-color: var(--background);
--background-color-hover: color-mix(in srgb, var(--background) 100%, transparent 50%);
}
&.ghost {
--background-color: transparent;
--border-color: transparent;
--color: var(--primary);

--background-color-hover: var(--gray-100);
--border-color-hover: transparent;
--color-hover: var(--primary);
}
}

.color-secondary {
Expand All @@ -167,6 +177,38 @@ const { theme } = useTheme();
--color-hover: var(--foreground);
--border-color-hover: var(--gray-400);
}
&.ghost {
--background-color: transparent;
--border-color: transparent;
--color: var(--foreground);

--background-color-hover: var(--gray-100);
--border-color-hover: transparent;
--color-hover: var(--foreground);
}
}

.ghost {
background-color: var(--background-color);
border-color: var(--border-color);
color: var(--color);
transition:
background-color var(--duration-150) var(--ease-out),
color var(--duration-150) var(--ease-out),
border-color var(--duration-150) var(--ease-out);

&:hover {
background-color: var(--background-color-hover);
border-color: var(--border-color-hover);
color: var(--color-hover);
}

&:focus-visible {
outline: none;
background-color: var(--background-color-hover);
color: var(--color-hover);
border-color: var(--border-color-hover);
}
}

.theme-dark {
Expand Down
136 changes: 136 additions & 0 deletions components/Block/Carousel/Carousel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<script setup lang="ts">
import Carousel from '@/components/Carousel/Carousel.vue';
import CarouselControls from '@/components/Carousel/CarouselControls.vue';
import CarouselDots from '~/components/Carousel/CarouselDots.vue';
import ClassNames from 'embla-carousel-class-names';

const { $directus, $readItem } = useNuxtApp();
const props = defineProps<{ uuid: string }>();
const block = ref<{ cards: Array<{ block_carousel_cards_id: string }> } | null>(null);

const fetchSlides = async () => {
const result = await $directus.request(
$readItem('block_carousel', props.uuid, {
fields: ['id', { cards: ['block_carousel_cards_id'] }],
}),
);

block.value = result as { cards: Array<{ block_carousel_cards_id: string }> };
};

onMounted(async () => {
await fetchSlides();
});
</script>

<template>
<div v-if="block" class="embla">
<Carousel
v-slot="{ current }"
:opts="{
loop: true,
}"
:plugins="[ClassNames({ snapped: 'slide--selected' })]"
>
<CarouselContent class="embla__container">
<CarouselItem v-for="(card, index) in block.cards" :key="card.block_carousel_cards_id" class="embla__slide">
<BlockCarouselCard :uuid="card.block_carousel_cards_id" :is-focused="current.value === index + 1" />
</CarouselItem>
</CarouselContent>
<CarouselControls v-slot="{ scrollPrev, scrollNext }">
<div class="embla__controls">
<BaseButton
color="secondary"
outline
class="embla__button embla__button--prev"
size="large"
icon="arrow_back"
icon-position="right"
aria-label="Previous slide"
@click="scrollPrev"
/>
<CarouselDots />
<BaseButton
color="secondary"
outline
class="embla__button embla__button--next"
size="large"
icon="arrow_forward"
icon-position="right"
aria-label="Next slide"
@click="scrollNext"
/>
</div>
</CarouselControls>
</Carousel>
</div>
</template>

<style lang="scss" scoped>
.embla {
margin: auto;
position: relative;
overflow: hidden;
padding: 50px 0;
height: 100%;
--slide-spacing: 60px;
--slide-size: 30%;

&:focus,
&:focus-within,
&:focus-visible {
outline: none;
}
&__container {
display: flex;
touch-action: pan-y pinch-zoom;
margin-left: calc(var(--slide-spacing) * -1);
}
&__slide {
position: relative;
transform: translate3d(0, 0, 0);
flex: 0 0 var(--slide-size);
min-width: 0;
flex-shrink: 0;
flex-grow: 0;
padding-left: var(--slide-spacing);
& > * {
opacity: 0.25;
transform-origin: center;
transition:
opacity 0.3s ease-in-out,
transform 0.3s ease-in-out;
}
&.slide--selected > * {
opacity: 1;
transform: scale(1.2);
}
}
&__controls {
display: flex;
justify-content: center;
gap: var(--space-16);
margin-top: var(--space-16);
align-items: center;
}

&__button {
padding: var(--space-2);
&__svg {
width: 24px;
height: 24px;
}
}
}
@media (max-width: 768px) {
.embla {
--slide-size: 100%;
--slide-spacing: var(--space-1);

&__slide {
flex: 0 0 var(--slide-size);
padding-left: var(--slide-spacing);
}
}
}
</style>
114 changes: 114 additions & 0 deletions components/Block/Carousel/CarouselCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<script setup lang="ts">
import type { BlockProps } from '../types';

const { $directus, $readItem } = useNuxtApp();
interface CarouselCardProps extends BlockProps {
uuid: string;
isFocused?: boolean;
}
const props = defineProps<CarouselCardProps>();

const { data: cardData } = useAsyncData(`carousel-card-${props.uuid}`, () =>
$directus.request(
$readItem('block_carousel_cards', props.uuid, {
fields: [
'id',
'type',
'title',
'image',
'external_url',
'button_text',
{ page: ['permalink'] },
{ resource: ['slug'] },
],
}),
),
);

const buttonHref = computed(() => {
if (cardData.value?.external_url) {
return cardData.value.external_url;
}

if (cardData.value?.page?.permalink) {
return cardData.value.page.permalink;
}

if (cardData.value?.resource?.slug) {
return `/resource/${cardData.value.resource.slug}`;
}

return '#';
});
</script>

<template>
<div :class="['carousel-card-content', { 'carousel-card--focused': props.isFocused }]">
<BaseDirectusImage v-if="cardData?.image" :uuid="cardData?.image as string" :alt="cardData?.title ?? ''" />
<Transition name="fade">
<div v-show="props.isFocused">
<h2 class="title">{{ cardData?.title }}</h2>
<BaseButton
v-show="props.isFocused"
:href="buttonHref"
:label="cardData?.button_text"
color="secondary"
ghost
class="custom-button"
size="medium"
icon="arrow_forward"
icon-position="right"
/>
</div>
</Transition>
</div>
</template>
<style lang="scss" scoped>
.carousel-card-content {
max-width: 100%;
border-radius: var(--rounded-xl);
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
img {
border-radius: var(--rounded-lg);
margin-bottom: var(--space-3);
}
h2 {
font-style: normal;
font-family: var(--family-display);
background: linear-gradient(143deg, var(--primary-500) 0%, var(--secondary) 100%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
position: relative;
z-index: 1;
max-width: var(--space-80);
word-wrap: break-word;
line-height: var(--line-height-2xl);
min-height: calc(var(--line-height-2xl) * 2);
overflow-wrap: break-word;
}
.custom-button {
margin-top: var(--space-3);
}
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease-in-out;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
@media (max-width: 768px) {
.carousel-card-content {
margin-left: var(--space-0);
img {
max-width: 70%;
margin-left: var(--space-0);
}
}
}
</style>
1 change: 1 addition & 0 deletions components/Block/LogoCloud.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ const logos = computed(() => {
<template>
<LogoGrid v-if="block && block.type === 'grid'" :logos="logos" />
<LogoTicker v-else-if="block && block.type === 'ticker'" :logos="logos" />
<LogoDoubleTicker v-else-if="block && block.type === 'double'" :logos="logos" />
<LogoTitle v-else-if="block && block.type === 'title'" :logos="logos as any" />
</template>
Loading
Loading