agentvibes 2.0.9 → 2.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/agent-vibes/bmad.md +203 -0
- package/.claude/github-star-reminder.txt +1 -0
- package/.claude/hooks/bmad-tts-injector.sh +333 -0
- package/.claude/hooks/bmad-voice-manager.sh +34 -0
- package/.claude/hooks/check-output-style.sh +2 -2
- package/.claude/hooks/github-star-reminder.sh +94 -0
- package/.claude/hooks/personality-manager.sh +2 -2
- package/.claude/hooks/piper-installer.sh +194 -0
- package/.claude/hooks/play-tts-elevenlabs.sh +30 -3
- package/.claude/hooks/play-tts-local-wrapper.sh +44 -0
- package/.claude/hooks/play-tts-piper.sh +10 -2
- package/.claude/hooks/play-tts-remote.sh +81 -0
- package/.claude/hooks/play-tts.sh +34 -0
- package/.claude/hooks/provider-commands.sh +30 -1
- package/.claude/hooks/voice-manager.sh +2 -2
- package/.claude/output-styles/agent-vibes.md +52 -36
- package/README.md +2 -2
- package/RELEASE_NOTES.md +412 -0
- package/agentvibes.org/.claude/commands/agent-vibes/add.md +21 -0
- package/agentvibes.org/.claude/commands/agent-vibes/agent-vibes.md +68 -0
- package/agentvibes.org/.claude/commands/agent-vibes/commands.json +53 -0
- package/agentvibes.org/.claude/commands/agent-vibes/get.md +9 -0
- package/agentvibes.org/.claude/commands/agent-vibes/list.md +13 -0
- package/agentvibes.org/.claude/commands/agent-vibes/personality.md +79 -0
- package/agentvibes.org/.claude/commands/agent-vibes/preview.md +16 -0
- package/agentvibes.org/.claude/commands/agent-vibes/provider.md +54 -0
- package/agentvibes.org/.claude/commands/agent-vibes/replay.md +19 -0
- package/agentvibes.org/.claude/commands/agent-vibes/sample.md +12 -0
- package/agentvibes.org/.claude/commands/agent-vibes/sentiment.md +52 -0
- package/agentvibes.org/.claude/commands/agent-vibes/set-language.md +47 -0
- package/agentvibes.org/.claude/commands/agent-vibes/set-pretext.md +65 -0
- package/agentvibes.org/.claude/commands/agent-vibes/switch.md +53 -0
- package/agentvibes.org/.claude/commands/agent-vibes/update.md +20 -0
- package/agentvibes.org/.claude/commands/agent-vibes/version.md +10 -0
- package/agentvibes.org/.claude/commands/agent-vibes/whoami.md +7 -0
- package/agentvibes.org/.claude/hooks/bmad-voice-manager.sh +278 -0
- package/agentvibes.org/.claude/hooks/language-manager.sh +190 -0
- package/agentvibes.org/.claude/hooks/personality-manager.sh +279 -0
- package/agentvibes.org/.claude/hooks/piper-download-voices.sh +133 -0
- package/agentvibes.org/.claude/hooks/piper-voice-manager.sh +227 -0
- package/agentvibes.org/.claude/hooks/play-tts-elevenlabs.sh +201 -0
- package/agentvibes.org/.claude/hooks/play-tts-piper.sh +175 -0
- package/agentvibes.org/.claude/hooks/play-tts.sh +138 -0
- package/agentvibes.org/.claude/hooks/provider-commands.sh +374 -0
- package/agentvibes.org/.claude/hooks/provider-manager.sh +196 -0
- package/agentvibes.org/.claude/hooks/sentiment-manager.sh +163 -0
- package/agentvibes.org/.claude/hooks/voice-manager.sh +349 -0
- package/agentvibes.org/.claude/hooks/voices-config.sh +33 -0
- package/agentvibes.org/.claude/journal/2025-10-07.html +373 -0
- package/agentvibes.org/.claude/journal/index.html +91 -0
- package/agentvibes.org/.claude/output-styles/agent-vibes.md +203 -0
- package/agentvibes.org/.claude/personalities/angry.md +16 -0
- package/agentvibes.org/.claude/personalities/annoying.md +16 -0
- package/agentvibes.org/.claude/personalities/crass.md +16 -0
- package/agentvibes.org/.claude/personalities/dramatic.md +16 -0
- package/agentvibes.org/.claude/personalities/dry-humor.md +52 -0
- package/agentvibes.org/.claude/personalities/flirty.md +22 -0
- package/agentvibes.org/.claude/personalities/funny.md +16 -0
- package/agentvibes.org/.claude/personalities/grandpa.md +34 -0
- package/agentvibes.org/.claude/personalities/millennial.md +16 -0
- package/agentvibes.org/.claude/personalities/moody.md +16 -0
- package/agentvibes.org/.claude/personalities/normal.md +18 -0
- package/agentvibes.org/.claude/personalities/pirate.md +16 -0
- package/agentvibes.org/.claude/personalities/poetic.md +16 -0
- package/agentvibes.org/.claude/personalities/professional.md +16 -0
- package/agentvibes.org/.claude/personalities/robot.md +16 -0
- package/agentvibes.org/.claude/personalities/sarcastic.md +40 -0
- package/agentvibes.org/.claude/personalities/sassy.md +16 -0
- package/agentvibes.org/.claude/personalities/surfer-dude.md +16 -0
- package/agentvibes.org/.claude/personalities/zen.md +16 -0
- package/agentvibes.org/.mcp-minimal.json +60 -0
- package/agentvibes.org/CHANGELOG.md +56 -0
- package/agentvibes.org/README.md +93 -0
- package/agentvibes.org/app/(auth)/layout.tsx +15 -0
- package/agentvibes.org/app/(auth)/reset-password/page.tsx +45 -0
- package/agentvibes.org/app/(auth)/signin/page.tsx +82 -0
- package/agentvibes.org/app/(auth)/signup/page.tsx +104 -0
- package/agentvibes.org/app/(default)/layout.tsx +31 -0
- package/agentvibes.org/app/(default)/page.tsx +20 -0
- package/agentvibes.org/app/api/hello/route.ts +3 -0
- package/agentvibes.org/app/css/additional-styles/theme.css +82 -0
- package/agentvibes.org/app/css/additional-styles/utility-patterns.css +55 -0
- package/agentvibes.org/app/css/style.css +100 -0
- package/agentvibes.org/app/layout.tsx +63 -0
- package/agentvibes.org/components/cta.tsx +58 -0
- package/agentvibes.org/components/features.tsx +256 -0
- package/agentvibes.org/components/hero-home.tsx +133 -0
- package/agentvibes.org/components/modal-video.tsx +137 -0
- package/agentvibes.org/components/page-illustration.tsx +55 -0
- package/agentvibes.org/components/spotlight.tsx +77 -0
- package/agentvibes.org/components/testimonials.tsx +282 -0
- package/agentvibes.org/components/ui/footer.tsx +82 -0
- package/agentvibes.org/components/ui/header.tsx +53 -0
- package/agentvibes.org/components/ui/logo.tsx +10 -0
- package/agentvibes.org/components/workflows.tsx +176 -0
- package/agentvibes.org/next.config.js +4 -0
- package/agentvibes.org/package-lock.json +1974 -0
- package/agentvibes.org/package.json +30 -0
- package/agentvibes.org/pnpm-lock.yaml +1141 -0
- package/agentvibes.org/postcss.config.js +5 -0
- package/agentvibes.org/public/audio/02-sarcastic.mp3 +0 -0
- package/agentvibes.org/public/audio/03-angry.mp3 +0 -0
- package/agentvibes.org/public/audio/04-grandpa.mp3 +0 -0
- package/agentvibes.org/public/audio/05-sarcastic-example2.mp3 +0 -0
- package/agentvibes.org/public/audio/french-rachel.mp3 +0 -0
- package/agentvibes.org/public/audio/spanish-antoni.mp3 +0 -0
- package/agentvibes.org/public/favicon.ico +0 -0
- package/agentvibes.org/public/fonts/nacelle-italic.woff2 +0 -0
- package/agentvibes.org/public/fonts/nacelle-regular.woff2 +0 -0
- package/agentvibes.org/public/fonts/nacelle-semibold.woff2 +0 -0
- package/agentvibes.org/public/fonts/nacelle-semibolditalic.woff2 +0 -0
- package/agentvibes.org/public/images/blurred-shape-gray.svg +1 -0
- package/agentvibes.org/public/images/blurred-shape.svg +1 -0
- package/agentvibes.org/public/images/client-logo-01.svg +1 -0
- package/agentvibes.org/public/images/client-logo-02.svg +1 -0
- package/agentvibes.org/public/images/client-logo-03.svg +1 -0
- package/agentvibes.org/public/images/client-logo-04.svg +1 -0
- package/agentvibes.org/public/images/client-logo-05.svg +1 -0
- package/agentvibes.org/public/images/client-logo-06.svg +1 -0
- package/agentvibes.org/public/images/client-logo-07.svg +1 -0
- package/agentvibes.org/public/images/client-logo-08.svg +1 -0
- package/agentvibes.org/public/images/client-logo-09.svg +1 -0
- package/agentvibes.org/public/images/features.png +0 -0
- package/agentvibes.org/public/images/footer-illustration.svg +1 -0
- package/agentvibes.org/public/images/hero-image-01.jpg +0 -0
- package/agentvibes.org/public/images/logo.svg +1 -0
- package/agentvibes.org/public/images/page-illustration.svg +1 -0
- package/agentvibes.org/public/images/secondary-illustration.svg +1 -0
- package/agentvibes.org/public/images/testimonial-01.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-02.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-03.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-04.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-05.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-06.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-07.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-08.jpg +0 -0
- package/agentvibes.org/public/images/testimonial-09.jpg +0 -0
- package/agentvibes.org/public/images/workflow-01.png +0 -0
- package/agentvibes.org/public/images/workflow-02.png +0 -0
- package/agentvibes.org/public/images/workflow-03.png +0 -0
- package/agentvibes.org/public/videos/video.mp4 +0 -0
- package/agentvibes.org/tsconfig.json +28 -0
- package/agentvibes.org/utils/useMasonry.tsx +67 -0
- package/agentvibes.org/utils/useMousePosition.tsx +27 -0
- package/docs/REMOTE_TTS_SETUP.md +190 -0
- package/package.json +2 -2
- package/src/installer.js +193 -9
- package/test/helpers/test-helper.bash +4 -2
- package/test/unit/personality-manager.bats +16 -4
- package/test/unit/personality-voice-mapping.bats +15 -6
- package/test/unit/play-tts.bats +0 -9
- package/.claude/commands/agent-vibes-bmad.md +0 -132
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useRef } from "react";
|
|
4
|
+
import type { StaticImageData } from "next/image";
|
|
5
|
+
import { Dialog, DialogBackdrop, DialogPanel } from "@headlessui/react";
|
|
6
|
+
import Image from "next/image";
|
|
7
|
+
import SecondaryIllustration from "@/public/images/secondary-illustration.svg";
|
|
8
|
+
|
|
9
|
+
interface ModalVideoProps {
|
|
10
|
+
thumb: StaticImageData;
|
|
11
|
+
thumbWidth: number;
|
|
12
|
+
thumbHeight: number;
|
|
13
|
+
thumbAlt: string;
|
|
14
|
+
video: string;
|
|
15
|
+
videoWidth: number;
|
|
16
|
+
videoHeight: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default function ModalVideo({
|
|
20
|
+
thumb,
|
|
21
|
+
thumbWidth,
|
|
22
|
+
thumbHeight,
|
|
23
|
+
thumbAlt,
|
|
24
|
+
video,
|
|
25
|
+
videoWidth,
|
|
26
|
+
videoHeight,
|
|
27
|
+
}: ModalVideoProps) {
|
|
28
|
+
const [modalOpen, setModalOpen] = useState<boolean>(false);
|
|
29
|
+
const videoRef = useRef<HTMLVideoElement>(null);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div className="relative">
|
|
33
|
+
{/* Secondary illustration */}
|
|
34
|
+
<div
|
|
35
|
+
className="pointer-events-none absolute bottom-8 left-1/2 -z-10 -ml-28 -translate-x-1/2 translate-y-1/2"
|
|
36
|
+
aria-hidden="true"
|
|
37
|
+
>
|
|
38
|
+
<Image
|
|
39
|
+
className="md:max-w-none"
|
|
40
|
+
src={SecondaryIllustration}
|
|
41
|
+
width={1165}
|
|
42
|
+
height={1012}
|
|
43
|
+
alt="Secondary illustration"
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
{/* Video thumbnail */}
|
|
48
|
+
<button
|
|
49
|
+
className="group relative flex items-center justify-center rounded-2xl focus:outline-hidden focus-visible:ring-3 focus-visible:ring-indigo-200"
|
|
50
|
+
onClick={() => {
|
|
51
|
+
setModalOpen(true);
|
|
52
|
+
}}
|
|
53
|
+
aria-label="Watch the video"
|
|
54
|
+
data-aos="fade-up"
|
|
55
|
+
data-aos-delay={200}
|
|
56
|
+
>
|
|
57
|
+
<figure className="relative overflow-hidden rounded-2xl before:absolute before:inset-0 before:-z-10 before:bg-linear-to-br before:from-gray-900 before:via-indigo-500/20 before:to-gray-900">
|
|
58
|
+
<Image
|
|
59
|
+
className="opacity-50 grayscale"
|
|
60
|
+
src={thumb}
|
|
61
|
+
width={thumbWidth}
|
|
62
|
+
height={thumbHeight}
|
|
63
|
+
priority
|
|
64
|
+
alt={thumbAlt}
|
|
65
|
+
/>
|
|
66
|
+
</figure>
|
|
67
|
+
{/* Play icon */}
|
|
68
|
+
<span className="pointer-events-none absolute p-2.5 before:absolute before:inset-0 before:rounded-full before:bg-gray-950 before:duration-300 group-hover:before:scale-110">
|
|
69
|
+
<span className="relative flex items-center gap-3">
|
|
70
|
+
<svg
|
|
71
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
72
|
+
width={20}
|
|
73
|
+
height={20}
|
|
74
|
+
fill="none"
|
|
75
|
+
>
|
|
76
|
+
<path
|
|
77
|
+
fill="url(#pla)"
|
|
78
|
+
fillRule="evenodd"
|
|
79
|
+
d="M10 20c5.523 0 10-4.477 10-10S15.523 0 10 0 0 4.477 0 10s4.477 10 10 10Zm3.5-10-5-3.5v7l5-3.5Z"
|
|
80
|
+
clipRule="evenodd"
|
|
81
|
+
/>
|
|
82
|
+
<defs>
|
|
83
|
+
<linearGradient
|
|
84
|
+
id="pla"
|
|
85
|
+
x1={10}
|
|
86
|
+
x2={10}
|
|
87
|
+
y1={0}
|
|
88
|
+
y2={20}
|
|
89
|
+
gradientUnits="userSpaceOnUse"
|
|
90
|
+
>
|
|
91
|
+
<stop stopColor="#6366F1" />
|
|
92
|
+
<stop offset={1} stopColor="#6366F1" stopOpacity=".72" />
|
|
93
|
+
</linearGradient>
|
|
94
|
+
</defs>
|
|
95
|
+
</svg>
|
|
96
|
+
<span className="text-sm font-medium leading-tight text-gray-300">
|
|
97
|
+
Watch Demo
|
|
98
|
+
<span className="text-gray-600"> - </span>
|
|
99
|
+
3:47
|
|
100
|
+
</span>
|
|
101
|
+
</span>
|
|
102
|
+
</span>
|
|
103
|
+
</button>
|
|
104
|
+
{/* End: Video thumbnail */}
|
|
105
|
+
|
|
106
|
+
<Dialog
|
|
107
|
+
initialFocus={videoRef}
|
|
108
|
+
open={modalOpen}
|
|
109
|
+
onClose={() => setModalOpen(false)}
|
|
110
|
+
>
|
|
111
|
+
<DialogBackdrop
|
|
112
|
+
transition
|
|
113
|
+
className="fixed inset-0 z-99999 bg-black/70 transition-opacity duration-300 ease-out data-closed:opacity-0"
|
|
114
|
+
/>
|
|
115
|
+
<div className="fixed inset-0 z-99999 flex px-4 py-6 sm:px-6">
|
|
116
|
+
<div className="mx-auto flex h-full max-w-6xl items-center">
|
|
117
|
+
<DialogPanel
|
|
118
|
+
transition
|
|
119
|
+
className="aspect-video max-h-full w-full overflow-hidden rounded-2xl bg-black shadow-2xl duration-300 ease-out data-closed:scale-95 data-closed:opacity-0"
|
|
120
|
+
>
|
|
121
|
+
<video
|
|
122
|
+
ref={videoRef}
|
|
123
|
+
width={videoWidth}
|
|
124
|
+
height={videoHeight}
|
|
125
|
+
loop
|
|
126
|
+
controls
|
|
127
|
+
>
|
|
128
|
+
<source src={video} type="video/mp4" />
|
|
129
|
+
Your browser does not support the video tag.
|
|
130
|
+
</video>
|
|
131
|
+
</DialogPanel>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</Dialog>
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import Image from "next/image";
|
|
2
|
+
import Illustration from "@/public/images/page-illustration.svg";
|
|
3
|
+
import BlurredShapeGray from "@/public/images/blurred-shape-gray.svg";
|
|
4
|
+
import BlurredShape from "@/public/images/blurred-shape.svg";
|
|
5
|
+
|
|
6
|
+
export default function PageIllustration({
|
|
7
|
+
multiple = false,
|
|
8
|
+
}: {
|
|
9
|
+
multiple?: boolean;
|
|
10
|
+
}) {
|
|
11
|
+
return (
|
|
12
|
+
<>
|
|
13
|
+
<div
|
|
14
|
+
className="pointer-events-none absolute left-1/2 top-0 -z-10 -translate-x-1/4"
|
|
15
|
+
aria-hidden="true"
|
|
16
|
+
>
|
|
17
|
+
<Image
|
|
18
|
+
className="max-w-none"
|
|
19
|
+
src={Illustration}
|
|
20
|
+
width={846}
|
|
21
|
+
height={594}
|
|
22
|
+
alt="Page illustration"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
{multiple && (
|
|
26
|
+
<>
|
|
27
|
+
<div
|
|
28
|
+
className="pointer-events-none absolute left-1/2 top-[400px] -z-10 -mt-20 -translate-x-full opacity-50"
|
|
29
|
+
aria-hidden="true"
|
|
30
|
+
>
|
|
31
|
+
<Image
|
|
32
|
+
className="max-w-none"
|
|
33
|
+
src={BlurredShapeGray}
|
|
34
|
+
width={760}
|
|
35
|
+
height={668}
|
|
36
|
+
alt="Blurred shape"
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
39
|
+
<div
|
|
40
|
+
className="pointer-events-none absolute left-1/2 top-[440px] -z-10 -translate-x-1/3"
|
|
41
|
+
aria-hidden="true"
|
|
42
|
+
>
|
|
43
|
+
<Image
|
|
44
|
+
className="max-w-none"
|
|
45
|
+
src={BlurredShape}
|
|
46
|
+
width={760}
|
|
47
|
+
height={668}
|
|
48
|
+
alt="Blurred shape"
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
</>
|
|
52
|
+
)}
|
|
53
|
+
</>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { useRef, useState, useEffect } from "react";
|
|
4
|
+
import useMousePosition from "@/utils/useMousePosition";
|
|
5
|
+
|
|
6
|
+
type SpotlightProps = {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
className?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default function Spotlight({
|
|
12
|
+
children,
|
|
13
|
+
className = "",
|
|
14
|
+
}: SpotlightProps) {
|
|
15
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
16
|
+
const mousePosition = useMousePosition();
|
|
17
|
+
const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
|
|
18
|
+
const containerSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 });
|
|
19
|
+
const [boxes, setBoxes] = useState<Array<HTMLElement>>([]);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
containerRef.current &&
|
|
23
|
+
setBoxes(
|
|
24
|
+
Array.from(containerRef.current.children).map(
|
|
25
|
+
(el) => el as HTMLElement,
|
|
26
|
+
),
|
|
27
|
+
);
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
initContainer();
|
|
32
|
+
window.addEventListener("resize", initContainer);
|
|
33
|
+
|
|
34
|
+
return () => {
|
|
35
|
+
window.removeEventListener("resize", initContainer);
|
|
36
|
+
};
|
|
37
|
+
}, [boxes]);
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
onMouseMove();
|
|
41
|
+
}, [mousePosition]);
|
|
42
|
+
|
|
43
|
+
const initContainer = () => {
|
|
44
|
+
if (containerRef.current) {
|
|
45
|
+
containerSize.current.w = containerRef.current.offsetWidth;
|
|
46
|
+
containerSize.current.h = containerRef.current.offsetHeight;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const onMouseMove = () => {
|
|
51
|
+
if (containerRef.current) {
|
|
52
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
53
|
+
const { w, h } = containerSize.current;
|
|
54
|
+
const x = mousePosition.x - rect.left;
|
|
55
|
+
const y = mousePosition.y - rect.top;
|
|
56
|
+
const inside = x < w && x > 0 && y < h && y > 0;
|
|
57
|
+
if (inside) {
|
|
58
|
+
mouse.current.x = x;
|
|
59
|
+
mouse.current.y = y;
|
|
60
|
+
boxes.forEach((box) => {
|
|
61
|
+
const boxX =
|
|
62
|
+
-(box.getBoundingClientRect().left - rect.left) + mouse.current.x;
|
|
63
|
+
const boxY =
|
|
64
|
+
-(box.getBoundingClientRect().top - rect.top) + mouse.current.y;
|
|
65
|
+
box.style.setProperty("--mouse-x", `${boxX}px`);
|
|
66
|
+
box.style.setProperty("--mouse-y", `${boxY}px`);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div className={className} ref={containerRef}>
|
|
74
|
+
{children}
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import useMasonry from "@/utils/useMasonry";
|
|
5
|
+
import Image, { StaticImageData } from "next/image";
|
|
6
|
+
import TestimonialImg01 from "@/public/images/testimonial-01.jpg";
|
|
7
|
+
import TestimonialImg02 from "@/public/images/testimonial-02.jpg";
|
|
8
|
+
import TestimonialImg03 from "@/public/images/testimonial-03.jpg";
|
|
9
|
+
import TestimonialImg04 from "@/public/images/testimonial-04.jpg";
|
|
10
|
+
import TestimonialImg05 from "@/public/images/testimonial-05.jpg";
|
|
11
|
+
import TestimonialImg06 from "@/public/images/testimonial-06.jpg";
|
|
12
|
+
import TestimonialImg07 from "@/public/images/testimonial-07.jpg";
|
|
13
|
+
import TestimonialImg08 from "@/public/images/testimonial-08.jpg";
|
|
14
|
+
import TestimonialImg09 from "@/public/images/testimonial-09.jpg";
|
|
15
|
+
import ClientImg01 from "@/public/images/client-logo-01.svg";
|
|
16
|
+
import ClientImg02 from "@/public/images/client-logo-02.svg";
|
|
17
|
+
import ClientImg03 from "@/public/images/client-logo-03.svg";
|
|
18
|
+
import ClientImg04 from "@/public/images/client-logo-04.svg";
|
|
19
|
+
import ClientImg05 from "@/public/images/client-logo-05.svg";
|
|
20
|
+
import ClientImg06 from "@/public/images/client-logo-06.svg";
|
|
21
|
+
import ClientImg07 from "@/public/images/client-logo-07.svg";
|
|
22
|
+
import ClientImg08 from "@/public/images/client-logo-08.svg";
|
|
23
|
+
import ClientImg09 from "@/public/images/client-logo-09.svg";
|
|
24
|
+
|
|
25
|
+
const testimonials = [
|
|
26
|
+
{
|
|
27
|
+
img: TestimonialImg01,
|
|
28
|
+
clientImg: ClientImg01,
|
|
29
|
+
name: "MaKayla P.",
|
|
30
|
+
company: "Disney",
|
|
31
|
+
content:
|
|
32
|
+
"As a content creator, I was always on the lookout for a tool that could help me keep up with the demand. The AI-driven content tool has been a game-changer. It generates high-quality content in a fraction of the time it used to take me.",
|
|
33
|
+
categories: [1, 3, 5],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
img: TestimonialImg02,
|
|
37
|
+
clientImg: ClientImg02,
|
|
38
|
+
name: "Andrew K.",
|
|
39
|
+
company: "Samsung",
|
|
40
|
+
content:
|
|
41
|
+
"I've tried several content generation tools, but this AI-driven tool is by far the best. It understands my brand's voice and consistently produces content that resonates with my audience!",
|
|
42
|
+
categories: [1, 2, 4],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
img: TestimonialImg03,
|
|
46
|
+
clientImg: ClientImg03,
|
|
47
|
+
name: "Lucy D.",
|
|
48
|
+
company: "Rio",
|
|
49
|
+
content:
|
|
50
|
+
"Content creation used to be a bottleneck in our workflow, but not anymore. This AI tool is intuitive and produces top-notch content every time. It's like having an extra team member who never sleeps! Definitely recommend.",
|
|
51
|
+
categories: [1, 2, 5],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
img: TestimonialImg04,
|
|
55
|
+
clientImg: ClientImg04,
|
|
56
|
+
name: "Pavel M.",
|
|
57
|
+
company: "Canon",
|
|
58
|
+
content:
|
|
59
|
+
"The quality of the content generated by this AI tool is outstanding. It has taken our content marketing to new heights, allowing us to publish more frequently without compromising on quality. Highly recommended for anyone.",
|
|
60
|
+
categories: [1, 4],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
img: TestimonialImg05,
|
|
64
|
+
clientImg: ClientImg05,
|
|
65
|
+
name: "Miriam E.",
|
|
66
|
+
company: "Cadbury",
|
|
67
|
+
content:
|
|
68
|
+
"The AI-driven content tool has been a lifesaver for my marketing agency. We can now produce high-quality content for multiple clients quickly and efficiently. It's an invaluable asset to our team.",
|
|
69
|
+
categories: [1, 3, 5],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
img: TestimonialImg06,
|
|
73
|
+
clientImg: ClientImg06,
|
|
74
|
+
name: "Eloise V.",
|
|
75
|
+
company: "Maffell",
|
|
76
|
+
content:
|
|
77
|
+
"I'm amazed at how well this AI-driven content tool performs. It's incredibly versatile and can generate content for blogs, social media, and even product descriptions effortlessly. It's fantastic!",
|
|
78
|
+
categories: [1, 3],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
img: TestimonialImg07,
|
|
82
|
+
clientImg: ClientImg07,
|
|
83
|
+
name: "Pierre-Gilles L.",
|
|
84
|
+
company: "Binance",
|
|
85
|
+
content:
|
|
86
|
+
"I was blown away by how easy it was to create my content using this tool! Within a few hours, I had a professional-looking platform up and running, and my client could not believe it.",
|
|
87
|
+
categories: [1, 2, 5],
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
img: TestimonialImg08,
|
|
91
|
+
clientImg: ClientImg08,
|
|
92
|
+
name: "Danielle K.",
|
|
93
|
+
company: "Forbes Inc.",
|
|
94
|
+
content:
|
|
95
|
+
"I've never been a fan of complicated website AI tools, which is why Open PRO is perfect for me. Its minimalist design and simple functionality make staying organized feel like second nature.",
|
|
96
|
+
categories: [1, 4],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
img: TestimonialImg09,
|
|
100
|
+
clientImg: ClientImg09,
|
|
101
|
+
name: "Mary P.",
|
|
102
|
+
company: "Ray Ban",
|
|
103
|
+
content:
|
|
104
|
+
"I've never been one for coding, so finding an AI tool that doesn't require any technical skills was a dream come true. This tool exceeded my expectations, and I'm proud to show off my new stuff to friends.",
|
|
105
|
+
categories: [1, 2],
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
export default function Testimonials() {
|
|
110
|
+
const masonryContainer = useMasonry();
|
|
111
|
+
const [category, setCategory] = useState<number>(1);
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<div className="mx-auto max-w-6xl px-4 sm:px-6">
|
|
115
|
+
<div className="border-t py-12 [border-image:linear-gradient(to_right,transparent,--theme(--color-slate-400/.25),transparent)1] md:py-20">
|
|
116
|
+
{/* Section header */}
|
|
117
|
+
<div className="mx-auto max-w-3xl pb-12 text-center">
|
|
118
|
+
<h2 className="animate-[gradient_6s_linear_infinite] bg-[linear-gradient(to_right,var(--color-gray-200),var(--color-indigo-200),var(--color-gray-50),var(--color-indigo-300),var(--color-gray-200))] bg-[length:200%_auto] bg-clip-text pb-4 font-nacelle text-3xl font-semibold text-transparent md:text-4xl">
|
|
119
|
+
Don't take our word for it
|
|
120
|
+
</h2>
|
|
121
|
+
<p className="text-lg text-indigo-200/65">
|
|
122
|
+
We provide tech-first solutions that empower decision-makers to
|
|
123
|
+
build healthier and happier workspaces from anywhere in the world.
|
|
124
|
+
</p>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<div>
|
|
128
|
+
{/* Buttons */}
|
|
129
|
+
<div className="flex justify-center pb-12 max-md:hidden md:pb-16">
|
|
130
|
+
<div className="relative inline-flex flex-wrap justify-center rounded-[1.25rem] bg-gray-800/40 p-1">
|
|
131
|
+
{/* Button #1 */}
|
|
132
|
+
<button
|
|
133
|
+
className={`flex h-8 flex-1 items-center gap-2.5 whitespace-nowrap rounded-full px-3 text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-3 focus-visible:ring-indigo-200 ${category === 1 ? "relative bg-linear-to-b from-gray-900 via-gray-800/60 to-gray-900 before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:border before:border-transparent before:[background:linear-gradient(to_bottom,--theme(--color-indigo-500/0),--theme(--color-indigo-500/.5))_border-box] before:[mask-composite:exclude_!important] before:[mask:linear-gradient(white_0_0)_padding-box,_linear-gradient(white_0_0)]" : "opacity-65 transition-opacity hover:opacity-90"}`}
|
|
134
|
+
aria-pressed={category === 1}
|
|
135
|
+
onClick={() => setCategory(1)}
|
|
136
|
+
>
|
|
137
|
+
<svg
|
|
138
|
+
className={`fill-current ${category === 1 ? "text-indigo-500" : "text-gray-600"}`}
|
|
139
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
140
|
+
width="16"
|
|
141
|
+
height={16}
|
|
142
|
+
>
|
|
143
|
+
<path d="M.062 10.003a1 1 0 0 1 1.947.455c-.019.08.01.152.078.19l5.83 3.333c.052.03.115.03.168 0l5.83-3.333a.163.163 0 0 0 .078-.188 1 1 0 0 1 1.947-.459 2.161 2.161 0 0 1-1.032 2.384l-5.83 3.331a2.168 2.168 0 0 1-2.154 0l-5.83-3.331a2.162 2.162 0 0 1-1.032-2.382Zm7.854-7.981-5.83 3.332a.17.17 0 0 0 0 .295l5.828 3.33c.054.031.118.031.17.002l5.83-3.333a.17.17 0 0 0 0-.294L8.085 2.023a.172.172 0 0 0-.17-.001ZM9.076.285l5.83 3.332c1.458.833 1.458 2.935 0 3.768l-5.83 3.333c-.667.38-1.485.38-2.153-.001l-5.83-3.332c-1.457-.833-1.457-2.935 0-3.767L6.925.285a2.173 2.173 0 0 1 2.15 0Z" />
|
|
144
|
+
</svg>
|
|
145
|
+
<span>View All</span>
|
|
146
|
+
</button>
|
|
147
|
+
{/* Button #2 */}
|
|
148
|
+
<button
|
|
149
|
+
className={`flex h-8 flex-1 items-center gap-2.5 whitespace-nowrap rounded-full px-3 text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-3 focus-visible:ring-indigo-200 ${category === 2 ? "relative bg-linear-to-b from-gray-900 via-gray-800/60 to-gray-900 before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:border before:border-transparent before:[background:linear-gradient(to_bottom,--theme(--color-indigo-500/0),--theme(--color-indigo-500/.5))_border-box] before:[mask-composite:exclude_!important] before:[mask:linear-gradient(white_0_0)_padding-box,_linear-gradient(white_0_0)]" : "opacity-65 transition-opacity hover:opacity-90"}`}
|
|
150
|
+
aria-pressed={category === 2}
|
|
151
|
+
onClick={() => setCategory(2)}
|
|
152
|
+
>
|
|
153
|
+
<svg
|
|
154
|
+
className={`fill-current ${category === 2 ? "text-indigo-500" : "text-gray-600"}`}
|
|
155
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
156
|
+
width="16"
|
|
157
|
+
height={16}
|
|
158
|
+
>
|
|
159
|
+
<path d="M6.5 3.5a1.5 1.5 0 1 1 3 0 1.5 1.5 0 0 1-3 0ZM9 6.855A3.502 3.502 0 0 0 8 0a3.5 3.5 0 0 0-1 6.855v1.656L5.534 9.65a3.5 3.5 0 1 0 1.229 1.578L8 10.267l1.238.962a3.5 3.5 0 1 0 1.229-1.578L9 8.511V6.855Zm2.303 4.74c.005-.005.01-.01.013-.016l.012-.016a1.5 1.5 0 1 1-.025.032ZM3.5 11A1.497 1.497 0 0 1 5 12.5 1.5 1.5 0 1 1 3.5 11Z" />
|
|
160
|
+
</svg>
|
|
161
|
+
<span>Web Apps</span>
|
|
162
|
+
</button>
|
|
163
|
+
{/* Button #3 */}
|
|
164
|
+
<button
|
|
165
|
+
className={`flex h-8 flex-1 items-center gap-2.5 whitespace-nowrap rounded-full px-3 text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-3 focus-visible:ring-indigo-200 ${category === 3 ? "relative bg-linear-to-b from-gray-900 via-gray-800/60 to-gray-900 before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:border before:border-transparent before:[background:linear-gradient(to_bottom,--theme(--color-indigo-500/0),--theme(--color-indigo-500/.5))_border-box] before:[mask-composite:exclude_!important] before:[mask:linear-gradient(white_0_0)_padding-box,_linear-gradient(white_0_0)]" : "opacity-65 transition-opacity hover:opacity-90"}`}
|
|
166
|
+
aria-pressed={category === 3}
|
|
167
|
+
onClick={() => setCategory(3)}
|
|
168
|
+
>
|
|
169
|
+
<svg
|
|
170
|
+
className={`fill-current ${category === 3 ? "text-indigo-500" : "text-gray-600"}`}
|
|
171
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
172
|
+
width="16"
|
|
173
|
+
height={16}
|
|
174
|
+
>
|
|
175
|
+
<path d="M2.428 10c.665-1.815 1.98-3.604 3.44-4.802-.6-1.807-1.443-3.079-2.29-3.18-1.91-.227-2.246 2.04-.174 2.962a1 1 0 1 1-.813 1.827C-1.407 5.028-.589-.491 3.815.032c1.605.191 2.925 1.811 3.79 4.07.979-.427 1.937-.51 2.735-.092.818.429 1.143 1.123 1.294 2.148.015.1.022.149.043.32.542-.537 1.003-.797 1.693-.622.64.162.894.493 1.195 1.147l.018.04a1 1 0 0 1 1.133 1.61c-.46.47-1.12.574-1.744.398a1.661 1.661 0 0 1-.87-.592 2.127 2.127 0 0 1-.224-.349 3.225 3.225 0 0 1-.55.477c-.377.253-.8.368-1.259.267-.993-.218-1.21-.779-1.367-2.05-.027-.22-.033-.262-.046-.353-.067-.452-.144-.617-.244-.67-.225-.118-.665-.013-1.206.278.297 1.243.475 2.587.516 3.941H15a1 1 0 0 1 0 2H8.68l-.025.285c-.173 1.918-.906 3.381-2.654 3.668-1.5.246-3.013-.47-3.677-1.858-.29-.637-.39-1.35-.342-2.095H1a1 1 0 0 1 0-2h1.428Zm2.11 0h2.175a18.602 18.602 0 0 0-.284-2.577c-.205.202-.408.42-.606.654A9.596 9.596 0 0 0 4.537 10Zm2.135 2H3.942c-.032.465.03.888.194 1.25.258.538.89.836 1.54.73.546-.09.888-.772.988-1.875L6.673 12Z" />
|
|
176
|
+
</svg>
|
|
177
|
+
<span>eCommerce</span>
|
|
178
|
+
</button>
|
|
179
|
+
{/* Button #4 */}
|
|
180
|
+
<button
|
|
181
|
+
className={`flex h-8 flex-1 items-center gap-2.5 whitespace-nowrap rounded-full px-3 text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-3 focus-visible:ring-indigo-200 ${category === 4 ? "relative bg-linear-to-b from-gray-900 via-gray-800/60 to-gray-900 before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:border before:border-transparent before:[background:linear-gradient(to_bottom,--theme(--color-indigo-500/0),--theme(--color-indigo-500/.5))_border-box] before:[mask-composite:exclude_!important] before:[mask:linear-gradient(white_0_0)_padding-box,_linear-gradient(white_0_0)]" : "opacity-65 transition-opacity hover:opacity-90"}`}
|
|
182
|
+
aria-pressed={category === 4}
|
|
183
|
+
onClick={() => setCategory(4)}
|
|
184
|
+
>
|
|
185
|
+
<svg
|
|
186
|
+
className={`fill-current ${category === 4 ? "text-indigo-500" : "text-gray-600"}`}
|
|
187
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
188
|
+
width="16"
|
|
189
|
+
height={16}
|
|
190
|
+
>
|
|
191
|
+
<path d="M3.757 3.758a6 6 0 0 1 8.485 8.485 5.992 5.992 0 0 1-5.301 1.664 1 1 0 1 0-.351 1.969 8 8 0 1 0-4.247-2.218 1 1 0 0 0 1.415-.001L9.12 8.294v1.827a1 1 0 1 0 2 0v-4.2a.997.997 0 0 0-1-1.042H5.879a1 1 0 1 0 0 2h1.829l-4.599 4.598a6 6 0 0 1 .648-7.719Z" />
|
|
192
|
+
</svg>
|
|
193
|
+
<span>Enteprise</span>
|
|
194
|
+
</button>
|
|
195
|
+
{/* Button #5 */}
|
|
196
|
+
<button
|
|
197
|
+
className={`flex h-8 flex-1 items-center gap-2.5 whitespace-nowrap rounded-full px-3 text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-3 focus-visible:ring-indigo-200 ${category === 5 ? "relative bg-linear-to-b from-gray-900 via-gray-800/60 to-gray-900 before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:border before:border-transparent before:[background:linear-gradient(to_bottom,--theme(--color-indigo-500/0),--theme(--color-indigo-500/.5))_border-box] before:[mask-composite:exclude_!important] before:[mask:linear-gradient(white_0_0)_padding-box,_linear-gradient(white_0_0)]" : "opacity-65 transition-opacity hover:opacity-90"}`}
|
|
198
|
+
aria-pressed={category === 5}
|
|
199
|
+
onClick={() => setCategory(5)}
|
|
200
|
+
>
|
|
201
|
+
<svg
|
|
202
|
+
className={`fill-current ${category === 5 ? "text-indigo-500" : "text-gray-600"}`}
|
|
203
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
204
|
+
width="16"
|
|
205
|
+
height={16}
|
|
206
|
+
>
|
|
207
|
+
<path d="M13.95.879a3 3 0 0 0-4.243 0L1.293 9.293a1 1 0 0 0-.274.51l-1 5a1 1 0 0 0 1.177 1.177l5-1a1 1 0 0 0 .511-.273l1.16-1.16a1 1 0 0 0-1.414-1.414l-.946.946-3.232.646.646-3.232 8.2-8.2a1 1 0 0 1 1.414 0l1.172 1.172a1 1 0 0 1 0 1.414l-.55.549a1 1 0 0 0 1.415 1.414l.55-.55a3 3 0 0 0 0-4.241L13.948.879ZM3.25 4.5a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5Zm11.474 6.029-1.521-.752-.752-1.521c-.168-.341-.73-.341-.896 0l-.752 1.52-1.521.753a.498.498 0 0 0 0 .896l1.52.752.753 1.52a.5.5 0 0 0 .896 0l.752-1.52 1.52-.752a.498.498 0 0 0 0-.896Z" />
|
|
208
|
+
</svg>
|
|
209
|
+
<span>Enteprise</span>
|
|
210
|
+
</button>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
{/* Cards */}
|
|
215
|
+
<div
|
|
216
|
+
className="mx-auto grid max-w-sm items-start gap-6 sm:max-w-none sm:grid-cols-2 lg:grid-cols-3"
|
|
217
|
+
ref={masonryContainer}
|
|
218
|
+
>
|
|
219
|
+
{testimonials.map((testimonial, index) => (
|
|
220
|
+
<div key={index} className="group">
|
|
221
|
+
<Testimonial testimonial={testimonial} category={category}>
|
|
222
|
+
{testimonial.content}
|
|
223
|
+
</Testimonial>
|
|
224
|
+
</div>
|
|
225
|
+
))}
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function Testimonial({
|
|
234
|
+
testimonial,
|
|
235
|
+
category,
|
|
236
|
+
children,
|
|
237
|
+
}: {
|
|
238
|
+
testimonial: {
|
|
239
|
+
img: StaticImageData;
|
|
240
|
+
clientImg: StaticImageData;
|
|
241
|
+
name: string;
|
|
242
|
+
company: string;
|
|
243
|
+
content: string;
|
|
244
|
+
categories: number[];
|
|
245
|
+
};
|
|
246
|
+
category: number;
|
|
247
|
+
children: React.ReactNode;
|
|
248
|
+
}) {
|
|
249
|
+
return (
|
|
250
|
+
<article
|
|
251
|
+
className={`relative rounded-2xl bg-linear-to-br from-gray-900/50 via-gray-800/25 to-gray-900/50 p-5 backdrop-blur-xs transition-opacity before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:border before:border-transparent before:[background:linear-gradient(to_right,var(--color-gray-800),var(--color-gray-700),var(--color-gray-800))_border-box] before:[mask-composite:exclude_!important] before:[mask:linear-gradient(white_0_0)_padding-box,_linear-gradient(white_0_0)] ${!testimonial.categories.includes(category) ? "opacity-30" : ""}`}
|
|
252
|
+
>
|
|
253
|
+
<div className="flex flex-col gap-4">
|
|
254
|
+
<div>
|
|
255
|
+
<Image src={testimonial.clientImg} height={36} alt="Client logo" />
|
|
256
|
+
</div>
|
|
257
|
+
<p className="text-indigo-200/65 before:content-['“'] after:content-['”']">
|
|
258
|
+
{children}
|
|
259
|
+
</p>
|
|
260
|
+
<div className="flex items-center gap-3">
|
|
261
|
+
<Image
|
|
262
|
+
className="inline-flex shrink-0 rounded-full"
|
|
263
|
+
src={testimonial.img}
|
|
264
|
+
width={36}
|
|
265
|
+
height={36}
|
|
266
|
+
alt={testimonial.name}
|
|
267
|
+
/>
|
|
268
|
+
<div className="text-sm font-medium text-gray-200">
|
|
269
|
+
<span>{testimonial.name}</span>
|
|
270
|
+
<span className="text-gray-700"> - </span>
|
|
271
|
+
<a
|
|
272
|
+
className="text-indigo-200/65 transition-colors hover:text-indigo-500"
|
|
273
|
+
href="#0"
|
|
274
|
+
>
|
|
275
|
+
{testimonial.company}
|
|
276
|
+
</a>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
</article>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import Logo from "./logo";
|
|
2
|
+
import Image from "next/image";
|
|
3
|
+
import FooterIllustration from "@/public/images/footer-illustration.svg";
|
|
4
|
+
|
|
5
|
+
export default function Footer() {
|
|
6
|
+
return (
|
|
7
|
+
<footer>
|
|
8
|
+
<div className="relative mx-auto max-w-6xl px-4 sm:px-6">
|
|
9
|
+
{/* Footer illustration */}
|
|
10
|
+
<div
|
|
11
|
+
className="pointer-events-none absolute bottom-0 left-1/2 -z-10 -translate-x-1/2"
|
|
12
|
+
aria-hidden="true"
|
|
13
|
+
>
|
|
14
|
+
<Image
|
|
15
|
+
className="max-w-none"
|
|
16
|
+
src={FooterIllustration}
|
|
17
|
+
width={1076}
|
|
18
|
+
height={378}
|
|
19
|
+
alt="Footer illustration"
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
22
|
+
<div className="py-8 md:py-12">
|
|
23
|
+
<div className="flex justify-between items-center mb-6">
|
|
24
|
+
<div className="mb-3">
|
|
25
|
+
<Logo />
|
|
26
|
+
</div>
|
|
27
|
+
<div className="text-sm">
|
|
28
|
+
<p className="mb-3 text-indigo-200/65">
|
|
29
|
+
© AgentVibes.org, All Rights Reserved
|
|
30
|
+
</p>
|
|
31
|
+
<ul className="inline-flex gap-1">
|
|
32
|
+
<li>
|
|
33
|
+
<a
|
|
34
|
+
className="flex items-center justify-center text-indigo-500 transition hover:text-indigo-400"
|
|
35
|
+
href="https://github.com/paulpreibisch/AgentVibes"
|
|
36
|
+
target="_blank"
|
|
37
|
+
rel="noopener noreferrer"
|
|
38
|
+
aria-label="Github"
|
|
39
|
+
>
|
|
40
|
+
<svg
|
|
41
|
+
className="h-8 w-8 fill-current"
|
|
42
|
+
viewBox="0 0 32 32"
|
|
43
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
44
|
+
>
|
|
45
|
+
<path d="M16 8.2c-4.4 0-8 3.6-8 8 0 3.5 2.3 6.5 5.5 7.6.4.1.5-.2.5-.4V22c-2.2.5-2.7-1-2.7-1-.4-.9-.9-1.2-.9-1.2-.7-.5.1-.5.1-.5.8.1 1.2.8 1.2.8.7 1.3 1.9.9 2.3.7.1-.5.3-.9.5-1.1-1.8-.2-3.6-.9-3.6-4 0-.9.3-1.6.8-2.1-.1-.2-.4-1 .1-2.1 0 0 .7-.2 2.2.8.6-.2 1.3-.3 2-.3s1.4.1 2 .3c1.5-1 2.2-.8 2.2-.8.4 1.1.2 1.9.1 2.1.5.6.8 1.3.8 2.1 0 3.1-1.9 3.7-3.7 3.9.3.4.6.9.6 1.6v2.2c0 .2.1.5.6.4 3.2-1.1 5.5-4.1 5.5-7.6-.1-4.4-3.7-8-8.1-8z" />
|
|
46
|
+
</svg>
|
|
47
|
+
</a>
|
|
48
|
+
</li>
|
|
49
|
+
</ul>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
{/* Disclaimer */}
|
|
54
|
+
<div className="border-t border-gray-800 pt-6 text-center">
|
|
55
|
+
<p className="text-xs text-indigo-200/50 max-w-4xl mx-auto inline-block">
|
|
56
|
+
<strong>Disclaimer:</strong> AgentVibes is not affiliated with, endorsed by, or officially connected to ElevenLabs, Anthropic, or Claude.
|
|
57
|
+
ElevenLabs API usage is subject to their{" "}
|
|
58
|
+
<a
|
|
59
|
+
href="https://elevenlabs.io/terms"
|
|
60
|
+
target="_blank"
|
|
61
|
+
rel="noopener noreferrer"
|
|
62
|
+
className="text-indigo-400 hover:text-indigo-300 underline"
|
|
63
|
+
>
|
|
64
|
+
terms of service
|
|
65
|
+
</a>
|
|
66
|
+
{" "}and{" "}
|
|
67
|
+
<a
|
|
68
|
+
href="https://elevenlabs.io/pricing"
|
|
69
|
+
target="_blank"
|
|
70
|
+
rel="noopener noreferrer"
|
|
71
|
+
className="text-indigo-400 hover:text-indigo-300 underline"
|
|
72
|
+
>
|
|
73
|
+
pricing
|
|
74
|
+
</a>
|
|
75
|
+
. Users are responsible for their own API costs. Provided "as-is" under Apache 2.0 License without warranty.
|
|
76
|
+
</p>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</footer>
|
|
81
|
+
);
|
|
82
|
+
}
|