Разделил на компоненты
All checks were successful
Gitea Actions Demo / build-and-deploy (push) Successful in 25s

This commit is contained in:
Opti1337 2024-04-18 21:46:59 +03:00
parent 250174211e
commit e823d9c322
3 changed files with 117 additions and 67 deletions

77
app.vue
View File

@ -4,23 +4,14 @@
</header> </header>
<div class="grid"> <div class="grid">
<div v-for="card in cards" ref="cardsELS" :key="card.title" class="card"> <AppCard v-for="card in cards" ref="cardEls" :key="card.title" v-bind="card" />
<p class="card__title">
{{ card.title }}
</p>
<img :src="card.img" alt="TeamSpeak" class="card__image">
<a class="button card__action" :href="card.href">
{{ card.action }}
</a>
</div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { onMounted, ref } from 'vue' import { onMounted, ref } from 'vue'
import { gsap } from 'gsap' import { gsap } from 'gsap'
import AppCard from '~/components/app-card.vue'
const cards = ref([ const cards = ref([
{ {
@ -55,7 +46,7 @@ const cards = ref([
}, },
]) ])
const cardsELS = ref([]) const cardEls = ref([])
const logoEl = ref() const logoEl = ref()
const DURATION = 0.3 const DURATION = 0.3
@ -70,20 +61,19 @@ const CARD_OPTIONS = {
} }
onMounted(() => { onMounted(() => {
const cards = cardsELS.value const groupsCount = Math.ceil((cardEls.value.length - 1) / 2)
const groupsCount = Math.ceil((cards.length - 1) / 2)
const t = gsap.timeline() const t = gsap.timeline()
if (cards[0]) if (cardEls.value[0])
t.to(cards[0], CARD_OPTIONS) t.to(cardEls.value[0].$el, CARD_OPTIONS)
for (let i = 0; i < groupsCount; i++) { for (let i = 0; i < groupsCount; i++) {
if (cards[i * 2 + 1]) if (cardEls.value[i * 2 + 1])
t.to(cards[i * 2 + 1], CARD_OPTIONS, `<${OVERLAP}`) t.to(cardEls.value[i * 2 + 1].$el, CARD_OPTIONS, `<${OVERLAP}`)
if (cards[i * 2 + 2]) if (cardEls.value[i * 2 + 2])
t.to(cards[i * 2 + 2], CARD_OPTIONS, `<<${OVERLAP}`) t.to(cardEls.value[i * 2 + 2].$el, CARD_OPTIONS, `<<${OVERLAP}`)
} }
t.fromTo( t.fromTo(
@ -124,51 +114,4 @@ header {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
} }
.card {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
justify-items: flex-start;
border-radius: 16px;
padding: 16px;
gap: 16px;
background-image: linear-gradient(135deg, var(--chocolate-cosmos), var(--black));
&__title {
font-size: 24px;
font-weight: 700;
}
&__image {
width: 80px;
grid-row: span 2;
opacity: 0.7;
}
&__action {
grid-row: 2;
}
}
.button {
display: inline-block;
text-decoration: none;
border: none;
border-radius: 8px;
padding: 8px 12px;
cursor: pointer;
background-image: linear-gradient(135deg, var(--beaver) 0%, var(--beaver) 51%, var(--walnut-brown) 110%);
background-size: 200% auto;
background-color: var(--walnut-brown);
background-repeat: repeat;
color: var(--white-smoke);
font-weight: 500;
transition: .15s ease-out;
transition-property: color, background-position;
&:hover:not(:active) {
background-position: right center;
}
}
</style> </style>

53
components/app-button.vue Normal file
View File

@ -0,0 +1,53 @@
<template>
<Component :is="tag" class="app-button" v-bind="attrs">
<slot />
</Component>
</template>
<script lang="ts" setup>
defineOptions({
name: 'AppButton',
})
const props = defineProps<{
href?: string
}>()
const isLink = computed(() => !!props.href)
const tag = computed(() => isLink.value ? 'a' : 'button')
const attrs = computed(() => {
if (isLink.value) {
return {
href: props.href,
}
}
else {
return {
type: 'button',
}
}
})
</script>
<style lang="scss">
.app-button {
display: inline-block;
text-decoration: none;
border: none;
border-radius: 8px;
padding: 8px 12px;
cursor: pointer;
background-image: linear-gradient(135deg, var(--beaver) 0%, var(--beaver) 51%, var(--walnut-brown) 110%);
background-size: 200% auto;
background-color: var(--walnut-brown);
background-repeat: repeat;
color: var(--white-smoke);
font-weight: 500;
transition: .15s ease-out;
transition-property: color, background-position;
&:hover:not(:active) {
background-position: right center;
}
}
</style>

54
components/app-card.vue Normal file
View File

@ -0,0 +1,54 @@
<template>
<div class="app-card">
<p class="app-card__title">
{{ title }}
</p>
<img :src="img" alt="TeamSpeak" class="app-card__image">
<AppButton class="app-card__action" :href="href">
{{ action }}
</AppButton>
</div>
</template>
<script lang="ts" setup>
defineOptions({
name: 'AppCard',
})
defineProps<{
title: string
action: string
href: string
img: string
}>()
</script>
<style lang="scss">
.app-card {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
justify-items: flex-start;
border-radius: 16px;
padding: 16px;
gap: 16px;
background-image: linear-gradient(135deg, var(--chocolate-cosmos), var(--black));
&__title {
font-size: 24px;
font-weight: 700;
}
&__image {
width: 80px;
grid-row: span 2;
opacity: 0.7;
}
&__action {
grid-row: 2;
}
}
</style>