优化
This commit is contained in:
91
monisuo-admin/src/components/marketing/evaluation.vue
Normal file
91
monisuo-admin/src/components/marketing/evaluation.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<script lang="ts" setup>
|
||||
import Marquee from '@/components/inspira-ui/marquee/index.vue'
|
||||
import MarqueeReviewCard from '@/components/inspira-ui/marquee/review-card.vue'
|
||||
|
||||
const reviews = [
|
||||
{
|
||||
name: 'Jack',
|
||||
username: '@jack',
|
||||
body: 'I\'ve never seen anything like this before. It\'s amazing. I love it.',
|
||||
img: 'https://avatar.vercel.sh/jack',
|
||||
},
|
||||
{
|
||||
name: 'Jill',
|
||||
username: '@jill',
|
||||
body: 'I don\'t know what to say. I\'m speechless. This is amazing.',
|
||||
img: 'https://avatar.vercel.sh/jill',
|
||||
},
|
||||
{
|
||||
name: 'John',
|
||||
username: '@john',
|
||||
body: 'I\'m at a loss for words. This is amazing. I love it.',
|
||||
img: 'https://avatar.vercel.sh/john',
|
||||
},
|
||||
{
|
||||
name: 'Jane',
|
||||
username: '@jane',
|
||||
body: 'I\'m at a loss for words. This is amazing. I love it.',
|
||||
img: 'https://avatar.vercel.sh/jane',
|
||||
},
|
||||
{
|
||||
name: 'Jenny',
|
||||
username: '@jenny',
|
||||
body: 'I\'m at a loss for words. This is amazing. I love it.',
|
||||
img: 'https://avatar.vercel.sh/jenny',
|
||||
},
|
||||
{
|
||||
name: 'James',
|
||||
username: '@james',
|
||||
body: 'I\'m at a loss for words. This is amazing. I love it.',
|
||||
img: 'https://avatar.vercel.sh/james',
|
||||
},
|
||||
]
|
||||
|
||||
// Split reviews into two rows
|
||||
const firstRow = ref(reviews.slice(0, reviews.length / 2))
|
||||
const secondRow = ref(reviews.slice(reviews.length / 2))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h2 class="text-4xl font-black my-4 text-center">
|
||||
{{ $t('marketing.evaluation.title') }}
|
||||
</h2>
|
||||
<h4 class="text-center mb-4">
|
||||
{{ $t('marketing.evaluation.subtitle') }}
|
||||
</h4>
|
||||
<div
|
||||
class="relative flex w-full flex-col items-center justify-center overflow-hidden"
|
||||
>
|
||||
<Marquee pause-on-hover class="[--duration:50s]">
|
||||
<MarqueeReviewCard
|
||||
v-for="review in firstRow"
|
||||
:key="review.username"
|
||||
:img="review.img"
|
||||
:name="review.name"
|
||||
:username="review.username"
|
||||
:body="review.body"
|
||||
/>
|
||||
</Marquee>
|
||||
|
||||
<Marquee reverse pause-on-hover class="[--duration:50s]">
|
||||
<MarqueeReviewCard
|
||||
v-for="review in secondRow"
|
||||
:key="review.username"
|
||||
:img="review.img"
|
||||
:name="review.name"
|
||||
:username="review.username"
|
||||
:body="review.body"
|
||||
/>
|
||||
</Marquee>
|
||||
|
||||
<!-- Left Gradient -->
|
||||
<div
|
||||
class="pointer-events-none absolute inset-y-0 left-0 w-1/3 bg-linear-to-r from-(--ui-bg) dark:from-(--ui-bg)"
|
||||
/>
|
||||
|
||||
<!-- Right Gradient -->
|
||||
<div
|
||||
class="pointer-events-none absolute inset-y-0 right-0 w-1/3 bg-linear-to-l from-(--ui-bg) dark:from-(--ui-bg)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
84
monisuo-admin/src/components/marketing/features.vue
Normal file
84
monisuo-admin/src/components/marketing/features.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<script lang="ts" setup>
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import GlowingEffect from '@/components/inspira-ui/glowing-effect.vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const gridItems = computed(() => [
|
||||
{
|
||||
icon: 'lucide:box',
|
||||
title: t('marketing.features.feature1.title'),
|
||||
description: t('marketing.features.feature1.description'),
|
||||
},
|
||||
{
|
||||
icon: 'lucide:settings',
|
||||
title: t('marketing.features.feature2.title'),
|
||||
description: t('marketing.features.feature2.description'),
|
||||
},
|
||||
{
|
||||
icon: 'lucide:sparkles',
|
||||
title: t('marketing.features.feature3.title'),
|
||||
description: t('marketing.features.feature3.description'),
|
||||
},
|
||||
{
|
||||
icon: 'lucide:search',
|
||||
title: t('marketing.features.feature4.title'),
|
||||
description: t('marketing.features.feature4.description'),
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h2 class="text-4xl font-bold text-center mb-8">
|
||||
{{ $t('marketing.features.title') }}
|
||||
</h2>
|
||||
|
||||
<ul
|
||||
class="grid grid-cols-1 grid-rows-none gap-4 overflow-auto xl:max-h-[56rem] xl:grid-rows-2 lg:gap-4 md:grid-cols-2 md:grid-rows-3"
|
||||
>
|
||||
<li
|
||||
v-for="item in gridItems"
|
||||
:key="item.title"
|
||||
:class="cn('min-h-[14rem] list-none')"
|
||||
>
|
||||
<div class="rounded-2.5xl relative h-full border p-2 md:rounded-3xl md:p-3">
|
||||
<GlowingEffect
|
||||
:spread="40"
|
||||
:glow="true"
|
||||
:disabled="false"
|
||||
:proximity="64"
|
||||
:inactive-zone="0.01"
|
||||
/>
|
||||
<div
|
||||
class="border-0.75 relative flex h-full flex-col justify-between gap-6 overflow-hidden rounded-xl p-6 md:p-6 dark:shadow-[0px_0px_27px_0px_#2D2D2D]"
|
||||
>
|
||||
<div class="relative flex flex-1 flex-col justify-between gap-3">
|
||||
<div class="w-fit rounded-lg border border-gray-600 p-2">
|
||||
<Icon
|
||||
class="size-4 text-black dark:text-neutral-500"
|
||||
:icon="item.icon"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<h3
|
||||
class="-tracking-4 text-balance pt-0.5 font-sans text-xl/[1.375rem] font-semibold text-black md:text-2xl/[1.875rem] dark:text-white"
|
||||
>
|
||||
{{ item.title }}
|
||||
</h3>
|
||||
<h2
|
||||
class="font-sans text-sm/[1.125rem] text-black md:text-base/[1.375rem] dark:text-neutral-400 [&_b]:md:font-semibold [&_strong]:md:font-semibold"
|
||||
>
|
||||
{{ item.description }}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
81
monisuo-admin/src/components/marketing/hero.vue
Normal file
81
monisuo-admin/src/components/marketing/hero.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<script lang="ts" setup>
|
||||
import Autoplay from 'embla-carousel-autoplay'
|
||||
|
||||
const images = [
|
||||
'https://picsum.photos/640/640?random=1',
|
||||
'https://picsum.photos/640/640?random=2',
|
||||
'https://picsum.photos/640/640?random=3',
|
||||
'https://picsum.photos/640/640?random=4',
|
||||
'https://picsum.photos/640/640?random=5',
|
||||
'https://picsum.photos/640/640?random=6',
|
||||
]
|
||||
|
||||
const users: { avatar: string, name: string, id: number }[] = [
|
||||
{ avatar: 'https://github.com/benjamincanac.png', name: 'Benjamin Canac', id: 1 },
|
||||
{ avatar: 'https://github.com/romhml.png', name: 'Benjamin Canac', id: 2 },
|
||||
{ avatar: 'https://github.com/noook.png', name: 'Benjamin Canac', id: 3 },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="flex gap-8 justify-between flex-col lg:flex-row">
|
||||
<aside class="w-full lg:w-1/3">
|
||||
<p class="text-4xl font-black relative">
|
||||
{{ $t('marketing.hero.title') }}
|
||||
</p>
|
||||
|
||||
<div class="font-bold mt-2 relative">
|
||||
{{ $t('marketing.hero.subtitle') }}
|
||||
</div>
|
||||
|
||||
<div class="flex gap-4 my-12 relative">
|
||||
<UiButton>
|
||||
{{ $t('marketing.hero.getMore') }}
|
||||
</UiButton>
|
||||
|
||||
<img
|
||||
src="@/assets/icons/arrow-dark.svg"
|
||||
alt=""
|
||||
class="dark:hidden block w-12 h-12 absolute top-[110%] left-8 -rotate-90"
|
||||
>
|
||||
<img
|
||||
src="@/assets/icons/arrow-light.svg"
|
||||
alt=""
|
||||
class="dark:block hidden w-12 h-12 absolute top-[110%] left-8 -rotate-90"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex gap-2">
|
||||
<UiAvatar v-for="user in users" :key="user.id">
|
||||
<UiAvatarImage :src="user.avatar" />
|
||||
</UiAvatar>
|
||||
</div>
|
||||
|
||||
<span class="font-black">
|
||||
{{ $t('marketing.hero.learnPeople') }}
|
||||
</span>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<aside class="w-full lg:w-2/3 lg:px-2">
|
||||
<UiCarousel
|
||||
:opts="{
|
||||
align: 'start',
|
||||
loop: true,
|
||||
}"
|
||||
:plugins="[Autoplay({
|
||||
delay: 2000,
|
||||
})]"
|
||||
>
|
||||
<UiCarouselContent>
|
||||
<UiCarouselItem v-for="image in images" :key="image" class="basis-1/3">
|
||||
<img :src="image" width="320" height="320" class="rounded-lg">
|
||||
</UiCarouselItem>
|
||||
</UiCarouselContent>
|
||||
<UiCarouselPrevious class="hidden lg:flex" />
|
||||
<UiCarouselNext class="hidden lg:flex" />
|
||||
</UiCarousel>
|
||||
</aside>
|
||||
</main>
|
||||
</template>
|
||||
42
monisuo-admin/src/components/marketing/logos.vue
Normal file
42
monisuo-admin/src/components/marketing/logos.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<script lang="ts" setup>
|
||||
import { Icon } from '@iconify/vue'
|
||||
|
||||
import Marquee from '@/components/inspira-ui/marquee/index.vue'
|
||||
|
||||
const types = [
|
||||
{ name: 'Nuxt', icon: 'simple-icons:nuxt' },
|
||||
{ name: 'Vue', icon: 'simple-icons:vitess' },
|
||||
{ name: 'Vite', icon: 'simple-icons:vite' },
|
||||
{ name: 'vitest', icon: 'simple-icons:vitest' },
|
||||
{ name: 'vscode', icon: 'simple-icons:visualstudiocode' },
|
||||
{ name: 'mysql', icon: 'simple-icons:mysql' },
|
||||
{ name: 'prisma', icon: 'simple-icons:prisma' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="relative flex w-full flex-col items-center justify-center overflow-hidden -rotate-3"
|
||||
>
|
||||
<Marquee pause-on-hover reverse class="[--duration:50s]">
|
||||
<div
|
||||
v-for="type in types"
|
||||
:key="type.name"
|
||||
class="flex items-center gap-2 mx-4"
|
||||
>
|
||||
<Icon :icon="type.icon" class="w-12 h-12" />
|
||||
<span class="font-black text-4xl">{{ type.name }}</span>
|
||||
</div>
|
||||
</Marquee>
|
||||
|
||||
<!-- Left Gradient -->
|
||||
<div
|
||||
class="pointer-events-none absolute inset-y-0 left-0 w-1/3 bg-linear-to-r from-(--ui-bg) dark:from-(--ui-bg)"
|
||||
/>
|
||||
|
||||
<!-- Right Gradient -->
|
||||
<div
|
||||
class="pointer-events-none absolute inset-y-0 right-0 w-1/3 bg-linear-to-l from-(--ui-bg) dark:from-(--ui-bg)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
141
monisuo-admin/src/components/marketing/pricing-plans/index.vue
Normal file
141
monisuo-admin/src/components/marketing/pricing-plans/index.vue
Normal file
@@ -0,0 +1,141 @@
|
||||
<script lang="ts" setup>
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
interface Plan {
|
||||
id: string | number
|
||||
title: string
|
||||
description: string
|
||||
badge?: string
|
||||
price: string
|
||||
unit: string
|
||||
discount: string
|
||||
recommendation?: boolean
|
||||
billing?: {
|
||||
cycle: string
|
||||
period: string
|
||||
}
|
||||
features: string[]
|
||||
}
|
||||
|
||||
const plans = computed<Plan[]>(() => [
|
||||
{
|
||||
id: 1,
|
||||
title: t('marketing.pricingPlans.hobby.title'),
|
||||
description: t('marketing.pricingPlans.hobby.description'),
|
||||
price: t('marketing.pricingPlans.hobby.price'),
|
||||
discount: t('marketing.pricingPlans.hobby.discount'),
|
||||
unit: t('marketing.pricingPlans.hobby.unit'),
|
||||
billing: {
|
||||
cycle: t('marketing.pricingPlans.hobby.billing.cycle'),
|
||||
period: t('marketing.pricingPlans.hobby.billing.period'),
|
||||
},
|
||||
features: [
|
||||
t('marketing.pricingPlans.hobby.features.feature1'),
|
||||
t('marketing.pricingPlans.hobby.features.feature2'),
|
||||
t('marketing.pricingPlans.hobby.features.feature3'),
|
||||
t('marketing.pricingPlans.hobby.features.feature4'),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
recommendation: true,
|
||||
title: t('marketing.pricingPlans.starter.title'),
|
||||
description: t('marketing.pricingPlans.starter.description'),
|
||||
price: t('marketing.pricingPlans.starter.price'),
|
||||
discount: t('marketing.pricingPlans.starter.discount'),
|
||||
unit: t('marketing.pricingPlans.starter.unit'),
|
||||
billing: {
|
||||
cycle: t('marketing.pricingPlans.starter.billing.cycle'),
|
||||
period: t('marketing.pricingPlans.starter.billing.period'),
|
||||
},
|
||||
features: [
|
||||
t('marketing.pricingPlans.starter.features.feature1'),
|
||||
t('marketing.pricingPlans.starter.features.feature2'),
|
||||
t('marketing.pricingPlans.starter.features.feature3'),
|
||||
t('marketing.pricingPlans.starter.features.feature4'),
|
||||
t('marketing.pricingPlans.starter.features.feature5'),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: t('marketing.pricingPlans.business.title'),
|
||||
description: t('marketing.pricingPlans.business.description'),
|
||||
price: t('marketing.pricingPlans.business.price'),
|
||||
discount: t('marketing.pricingPlans.business.discount'),
|
||||
unit: t('marketing.pricingPlans.business.unit'),
|
||||
billing: {
|
||||
cycle: t('marketing.pricingPlans.business.billing.cycle'),
|
||||
period: t('marketing.pricingPlans.business.billing.period'),
|
||||
},
|
||||
features: [
|
||||
t('marketing.pricingPlans.business.features.feature1'),
|
||||
t('marketing.pricingPlans.business.features.feature2'),
|
||||
t('marketing.pricingPlans.business.features.feature3'),
|
||||
t('marketing.pricingPlans.business.features.feature4'),
|
||||
t('marketing.pricingPlans.business.features.feature5'),
|
||||
t('marketing.pricingPlans.business.features.feature6'),
|
||||
],
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="pricing-plans">
|
||||
<h2 class="text-center font-black my-4 text-4xl">
|
||||
{{ $t('marketing.pricingPlans.title') }}
|
||||
</h2>
|
||||
<h4 class="text-center text-xl">
|
||||
{{ $t('marketing.pricingPlans.subtitle') }}
|
||||
</h4>
|
||||
<div
|
||||
class="flex flex-col lg:flex-row lg:items-start items-center justify-center gap-4 mt-8"
|
||||
>
|
||||
<UiCard
|
||||
v-for="plan in plans"
|
||||
:key="plan.id"
|
||||
class="w-full lg:w-1/5"
|
||||
:class="{
|
||||
'border-2 border-primary bg-primary/10':
|
||||
plan.recommendation,
|
||||
}"
|
||||
>
|
||||
<h3 class="text-xl font-black text-center">
|
||||
{{ plan.title }}
|
||||
</h3>
|
||||
<div class="text-sm text-center text-neutral-400">
|
||||
{{ plan.description }}
|
||||
</div>
|
||||
|
||||
<div class="flex items-top my-2 justify-center">
|
||||
<div class="text-2xl font-black">
|
||||
{{ plan.unit }}
|
||||
<span class="text-4xl">{{ plan.price }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="plan.discount"
|
||||
class="text-sm font-bold line-through text-neutral-400"
|
||||
>
|
||||
{{ plan.unit }}{{ plan.discount }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-sm mb-4 text-center">
|
||||
<ul>
|
||||
<li v-for="feature in plan.features" :key="feature" class="mb-1">
|
||||
<Icon icon="carbon:checkmark" class="inline-block" />
|
||||
{{ feature }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="flex justify-center mx-8">
|
||||
<UiButton block>
|
||||
{{ $t('marketing.pricingPlans.buy') }}
|
||||
</UiButton>
|
||||
</div>
|
||||
</UiCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
34
monisuo-admin/src/components/marketing/setup.vue
Normal file
34
monisuo-admin/src/components/marketing/setup.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import Ripple from '@/components/inspira-ui/ripple/index.vue'
|
||||
import SignInButton from '@/components/sign-in-button.vue'
|
||||
import SignUpButton from '@/components/sign-up-button.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="relative flex h-[450px] w-full flex-col items-center justify-center overflow-hidden rounded-lg lg:w-full md:w-full"
|
||||
>
|
||||
<p class="z-10 whitespace-pre-wrap text-center text-5xl font-medium tracking-tighter text-black dark:text-white">
|
||||
{{ $t('marketing.setup.title') }}
|
||||
</p>
|
||||
<small class="mt-2">
|
||||
{{ $t('marketing.setup.subtitle') }}
|
||||
</small>
|
||||
|
||||
<div class="flex items-center gap-3 my-2 z-100">
|
||||
<SignInButton />
|
||||
<SignUpButton />
|
||||
</div>
|
||||
|
||||
<Ripple
|
||||
class="bg-white/5 mask-[linear-gradient(to_bottom,white,transparent)]"
|
||||
circle-class="border-[hsl(var(--primary))] bg-primary/25 blobed"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.blobed) {
|
||||
border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user