feat: docs.pivoine.art
This commit is contained in:
445
Projects/docs.pivoine.art/app/components/icons/KomposeIcon.vue
Executable file
445
Projects/docs.pivoine.art/app/components/icons/KomposeIcon.vue
Executable file
@@ -0,0 +1,445 @@
|
||||
<template>
|
||||
<div
|
||||
class="kompose-icon-wrapper"
|
||||
:class="{ 'is-clicked': isClicked, 'is-interactive': interactive }"
|
||||
@click="handleClick"
|
||||
@mouseenter="handleHover"
|
||||
@mouseleave="handleLeave"
|
||||
@touchstart="handleTouch"
|
||||
:style="{ width: size, height: size }"
|
||||
>
|
||||
<svg
|
||||
class="kompose-icon"
|
||||
viewBox="0 0 192 192"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<defs>
|
||||
<pattern id="carbon192" x="0" y="0" width="7.68" height="7.68" patternUnits="userSpaceOnUse">
|
||||
<rect width="7.68" height="7.68" fill="#0a0e27"></rect>
|
||||
<path d="M0,0 L3.84,3.84 M3.84,0 L7.68,3.84 M0,3.84 L3.84,7.68" stroke="#060815" stroke-width="1.5" opacity="0.5"></path>
|
||||
</pattern>
|
||||
|
||||
<linearGradient id="bgGrad192" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#1a1d2e;stop-opacity:1"></stop>
|
||||
<stop offset="100%" style="stop-color:#0a0e27;stop-opacity:1"></stop>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="primaryGrad192" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" class="gradient-start" style="stop-color:#00DC82;stop-opacity:1"></stop>
|
||||
<stop offset="100%" class="gradient-end" style="stop-color:#00a86b;stop-opacity:1"></stop>
|
||||
</linearGradient>
|
||||
|
||||
<filter id="glow192">
|
||||
<feGaussianBlur stdDeviation="6" result="coloredBlur"></feGaussianBlur>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredBlur"></feMergeNode>
|
||||
<feMergeNode in="SourceGraphic"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
|
||||
<filter id="intenseglow192">
|
||||
<feGaussianBlur stdDeviation="12" result="coloredBlur"></feGaussianBlur>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredBlur"></feMergeNode>
|
||||
<feMergeNode in="SourceGraphic"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- Background -->
|
||||
<rect class="bg-rect" width="192" height="192" rx="24" fill="url(#bgGrad192)"></rect>
|
||||
<rect class="carbon-pattern" width="192" height="192" rx="24" fill="url(#carbon192)" opacity="0.4"></rect>
|
||||
|
||||
<!-- Stylized K -->
|
||||
<g class="k-letter" transform="translate(48, 48)">
|
||||
<line class="k-line k-vertical" x1="0" y1="0" x2="0" y2="96" stroke="url(#primaryGrad192)" stroke-width="15" stroke-linecap="round" filter="url(#glow192)"></line>
|
||||
<line class="k-line k-diagonal-top" x1="0" y1="48" x2="57.6" y2="0" stroke="url(#primaryGrad192)" stroke-width="15" stroke-linecap="round" filter="url(#glow192)"></line>
|
||||
<line class="k-line k-diagonal-bottom" x1="0" y1="48" x2="57.6" y2="96" stroke="url(#primaryGrad192)" stroke-width="15" stroke-linecap="round" filter="url(#glow192)"></line>
|
||||
</g>
|
||||
|
||||
<!-- Animated status dot -->
|
||||
<circle class="status-dot" cx="163.2" cy="163.2" r="11.52" fill="#00DC82" opacity="0.9"></circle>
|
||||
<circle class="status-ring" cx="163.2" cy="163.2" r="17.28" fill="none" stroke="#00DC82" stroke-width="3" opacity="0.3"></circle>
|
||||
|
||||
<!-- Tech corners -->
|
||||
<line class="corner corner-tl-h" x1="15.36" y1="15.36" x2="28.8" y2="15.36" stroke="#00DC82" stroke-width="3" opacity="0.4"></line>
|
||||
<line class="corner corner-tl-v" x1="15.36" y1="15.36" x2="15.36" y2="28.8" stroke="#00DC82" stroke-width="3" opacity="0.4"></line>
|
||||
<line class="corner corner-tr-h" x1="176.64" y1="15.36" x2="163.2" y2="15.36" stroke="#00DC82" stroke-width="3" opacity="0.4"></line>
|
||||
<line class="corner corner-tr-v" x1="176.64" y1="15.36" x2="176.64" y2="28.8" stroke="#00DC82" stroke-width="3" opacity="0.4"></line>
|
||||
</svg>
|
||||
|
||||
<!-- Ripple effect container -->
|
||||
<div class="ripple" v-if="showRipple"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
interface Props {
|
||||
size?: string
|
||||
interactive?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: '192px',
|
||||
interactive: true
|
||||
})
|
||||
|
||||
const isClicked = ref(false)
|
||||
const showRipple = ref(false)
|
||||
|
||||
const handleClick = () => {
|
||||
if (!props.interactive) return
|
||||
|
||||
isClicked.value = true
|
||||
showRipple.value = true
|
||||
|
||||
setTimeout(() => {
|
||||
isClicked.value = false
|
||||
}, 600)
|
||||
|
||||
setTimeout(() => {
|
||||
showRipple.value = false
|
||||
}, 800)
|
||||
}
|
||||
|
||||
const handleHover = () => {
|
||||
if (!props.interactive) return
|
||||
// Hover animations are handled by CSS
|
||||
}
|
||||
|
||||
const handleLeave = () => {
|
||||
if (!props.interactive) return
|
||||
// Leave animations are handled by CSS
|
||||
}
|
||||
|
||||
const handleTouch = (e: TouchEvent) => {
|
||||
if (!props.interactive) return
|
||||
handleClick()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.kompose-icon-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper:not(.is-interactive) {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.kompose-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
filter: drop-shadow(0 4px 20px rgba(0, 220, 130, 0.2));
|
||||
transition: filter 0.4s ease;
|
||||
}
|
||||
|
||||
/* Hover Effects */
|
||||
.kompose-icon-wrapper.is-interactive:hover {
|
||||
transform: scale(1.05) translateY(-2px);
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .kompose-icon {
|
||||
filter: drop-shadow(0 8px 30px rgba(0, 220, 130, 0.4));
|
||||
animation: subtle-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .bg-rect {
|
||||
fill: url(#bgGrad192);
|
||||
opacity: 1;
|
||||
animation: bg-glow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .k-letter {
|
||||
animation: letter-glow 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .k-vertical {
|
||||
animation: line-slide-vertical 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .k-diagonal-top {
|
||||
animation: line-slide-diagonal-top 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) 0.1s;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .k-diagonal-bottom {
|
||||
animation: line-slide-diagonal-bottom 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) 0.2s;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .status-dot {
|
||||
animation: pulse-expand 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .status-ring {
|
||||
animation: ring-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .corner {
|
||||
opacity: 1 !important;
|
||||
stroke: #00DC82;
|
||||
animation: corner-extend 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
/* Click/Active Effects */
|
||||
.kompose-icon-wrapper.is-clicked {
|
||||
animation: click-bounce 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-clicked .kompose-icon {
|
||||
animation: rotate-3d 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
filter: drop-shadow(0 12px 40px rgba(0, 220, 130, 0.6));
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-clicked .k-letter {
|
||||
animation: letter-flash 0.6s ease-out;
|
||||
filter: url(#intenseglow192);
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-clicked .status-dot {
|
||||
animation: dot-burst 0.6s ease-out;
|
||||
}
|
||||
|
||||
/* Ripple Effect */
|
||||
.ripple {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(0, 220, 130, 0.6) 0%, rgba(0, 220, 130, 0) 70%);
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
animation: ripple-expand 0.8s ease-out;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Default animations for status dot */
|
||||
.status-dot {
|
||||
animation: default-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.status-ring {
|
||||
animation: default-ring-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Keyframe Animations */
|
||||
@keyframes subtle-pulse {
|
||||
0%, 100% {
|
||||
filter: drop-shadow(0 8px 30px rgba(0, 220, 130, 0.4));
|
||||
}
|
||||
50% {
|
||||
filter: drop-shadow(0 8px 35px rgba(0, 220, 130, 0.6));
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bg-glow {
|
||||
0%, 100% {
|
||||
filter: brightness(1);
|
||||
}
|
||||
50% {
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes letter-glow {
|
||||
0%, 100% {
|
||||
filter: url(#glow192);
|
||||
}
|
||||
50% {
|
||||
filter: url(#intenseglow192);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes line-slide-vertical {
|
||||
0% {
|
||||
stroke-dasharray: 96;
|
||||
stroke-dashoffset: 96;
|
||||
}
|
||||
100% {
|
||||
stroke-dasharray: 96;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes line-slide-diagonal-top {
|
||||
0% {
|
||||
stroke-dasharray: 68;
|
||||
stroke-dashoffset: 68;
|
||||
}
|
||||
100% {
|
||||
stroke-dasharray: 68;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes line-slide-diagonal-bottom {
|
||||
0% {
|
||||
stroke-dasharray: 68;
|
||||
stroke-dashoffset: 68;
|
||||
}
|
||||
100% {
|
||||
stroke-dasharray: 68;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse-expand {
|
||||
0%, 100% {
|
||||
r: 11.52;
|
||||
opacity: 0.9;
|
||||
}
|
||||
50% {
|
||||
r: 14;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ring-pulse {
|
||||
0%, 100% {
|
||||
r: 17.28;
|
||||
opacity: 0.3;
|
||||
stroke-width: 3;
|
||||
}
|
||||
50% {
|
||||
r: 20;
|
||||
opacity: 0.6;
|
||||
stroke-width: 2;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes corner-extend {
|
||||
0% {
|
||||
stroke-dasharray: 13.44;
|
||||
stroke-dashoffset: 13.44;
|
||||
}
|
||||
100% {
|
||||
stroke-dasharray: 13.44;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes click-bounce {
|
||||
0% {
|
||||
transform: scale(1) translateY(0) rotateY(0deg);
|
||||
}
|
||||
30% {
|
||||
transform: scale(0.92) translateY(0) rotateY(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.08) translateY(-4px) rotateY(180deg);
|
||||
}
|
||||
70% {
|
||||
transform: scale(0.98) translateY(0) rotateY(360deg);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1) translateY(0) rotateY(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate-3d {
|
||||
0% {
|
||||
transform: perspective(800px) rotateY(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: perspective(800px) rotateY(180deg);
|
||||
}
|
||||
100% {
|
||||
transform: perspective(800px) rotateY(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes letter-flash {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
20%, 60% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
40%, 80% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dot-burst {
|
||||
0% {
|
||||
r: 11.52;
|
||||
opacity: 0.9;
|
||||
}
|
||||
50% {
|
||||
r: 20;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
r: 11.52;
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ripple-expand {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(2.5);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes default-pulse {
|
||||
0%, 100% {
|
||||
opacity: 0.6;
|
||||
r: 11.52;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
r: 13.44;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes default-ring-pulse {
|
||||
0%, 100% {
|
||||
opacity: 0.3;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.kompose-icon-wrapper.is-interactive:hover {
|
||||
transform: scale(1.03) translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reduced motion support */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.kompose-icon-wrapper,
|
||||
.kompose-icon,
|
||||
.kompose-icon *,
|
||||
.ripple {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch device optimizations */
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
.kompose-icon-wrapper.is-interactive:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
47
Projects/docs.pivoine.art/app/globals.css
Normal file
47
Projects/docs.pivoine.art/app/globals.css
Normal file
@@ -0,0 +1,47 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
/* Custom animations */
|
||||
--animate-pulse: pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
|
||||
/* Custom keyframes for pulse */
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
outline-color: color-mix(in oklab, var(--ring) 50%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
border-color: var(--border);
|
||||
outline-color: var(--ring);
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom scrollbar styling */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: rgb(17 24 39);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgb(139 92 246);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgb(167 139 250);
|
||||
}
|
||||
42
Projects/docs.pivoine.art/app/layout.tsx
Normal file
42
Projects/docs.pivoine.art/app/layout.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { Inter } from 'next/font/google'
|
||||
import './globals.css'
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] })
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Pivoine Docs - Documentation Hub',
|
||||
description: 'Comprehensive documentation hub for all Pivoine projects by Valknar. Explore technical guides, API references, and tutorials.',
|
||||
keywords: ['documentation', 'pivoine', 'valknar', 'developer', 'guides', 'api'],
|
||||
authors: [{ name: 'Valknar', url: 'https://pivoine.art' }],
|
||||
creator: 'Valknar',
|
||||
openGraph: {
|
||||
type: 'website',
|
||||
locale: 'en_US',
|
||||
url: 'https://docs.pivoine.art',
|
||||
title: 'Pivoine Docs - Documentation Hub',
|
||||
description: 'Comprehensive documentation hub for all Pivoine projects',
|
||||
siteName: 'Pivoine Docs',
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: 'Pivoine Docs - Documentation Hub',
|
||||
description: 'Comprehensive documentation hub for all Pivoine projects',
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
},
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en" className="scroll-smooth">
|
||||
<body className={inter.className}>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
191
Projects/docs.pivoine.art/app/page.tsx
Normal file
191
Projects/docs.pivoine.art/app/page.tsx
Normal file
@@ -0,0 +1,191 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { BookOpen, Code2, Globe, ChevronRight, Sparkles, Terminal } from 'lucide-react'
|
||||
|
||||
export default function DocsHub() {
|
||||
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 })
|
||||
const [isHovering, setIsHovering] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
setMousePosition({
|
||||
x: (e.clientX / window.innerWidth) * 20 - 10,
|
||||
y: (e.clientY / window.innerHeight) * 20 - 10,
|
||||
})
|
||||
}
|
||||
window.addEventListener('mousemove', handleMouseMove)
|
||||
return () => window.removeEventListener('mousemove', handleMouseMove)
|
||||
}, [])
|
||||
|
||||
const projects = [
|
||||
{
|
||||
name: 'Kompose',
|
||||
status: 'Active',
|
||||
description: 'Comprehensive documentation for Kompose project',
|
||||
url: '/kompose',
|
||||
gradient: 'from-violet-500 to-purple-600'
|
||||
}
|
||||
]
|
||||
|
||||
const links = [
|
||||
{
|
||||
title: "Valknar's Blog",
|
||||
icon: Globe,
|
||||
url: 'http://pivoine.art',
|
||||
gradient: 'from-pink-500 to-rose-600'
|
||||
},
|
||||
{
|
||||
title: 'Source Code',
|
||||
icon: Code2,
|
||||
url: 'https://code.pivoine.art',
|
||||
gradient: 'from-cyan-500 to-blue-600'
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-gray-900 via-purple-900/20 to-gray-900 text-white overflow-hidden">
|
||||
{/* Animated background orbs */}
|
||||
<div className="fixed inset-0 overflow-hidden pointer-events-none">
|
||||
<div
|
||||
className="absolute w-96 h-96 bg-purple-500/20 rounded-full blur-3xl top-0 -left-48 animate-pulse"
|
||||
style={{
|
||||
transform: `translate(${mousePosition.x}px, ${mousePosition.y}px)`,
|
||||
transition: 'transform 0.3s ease-out'
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="absolute w-96 h-96 bg-pink-500/20 rounded-full blur-3xl bottom-0 -right-48 animate-pulse"
|
||||
style={{
|
||||
transform: `translate(${-mousePosition.x}px, ${-mousePosition.y}px)`,
|
||||
transition: 'transform 0.3s ease-out',
|
||||
animationDelay: '1s'
|
||||
}}
|
||||
/>
|
||||
<div className="absolute w-96 h-96 bg-cyan-500/10 rounded-full blur-3xl top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 animate-pulse" style={{ animationDelay: '0.5s' }} />
|
||||
</div>
|
||||
|
||||
{/* Main content */}
|
||||
<div className="relative z-10 container mx-auto px-6 py-12 max-w-6xl">
|
||||
{/* Header */}
|
||||
<header className="text-center mb-20 pt-12">
|
||||
<div className="inline-flex items-center gap-2 mb-6 px-4 py-2 bg-white/5 backdrop-blur-sm rounded-full border border-white/10">
|
||||
<Sparkles className="w-4 h-4 text-purple-400" />
|
||||
<span className="text-sm text-purple-300">Documentation Hub</span>
|
||||
</div>
|
||||
|
||||
<h1 className="text-7xl font-bold mb-6 bg-gradient-to-r from-white via-purple-200 to-pink-200 bg-clip-text text-transparent animate-pulse">
|
||||
Pivoine Docs
|
||||
</h1>
|
||||
|
||||
<p className="text-xl text-gray-300 max-w-2xl mx-auto leading-relaxed">
|
||||
Comprehensive documentation for all projects by <span className="text-purple-400 font-semibold">Valknar</span>.
|
||||
Explore technical guides, API references, and tutorials.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
{/* Projects Grid */}
|
||||
<section className="mb-20">
|
||||
<div className="flex items-center gap-3 mb-8">
|
||||
<Terminal className="w-6 h-6 text-purple-400" />
|
||||
<h2 className="text-3xl font-bold">Project Documentation</h2>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{projects.map((project, idx) => (
|
||||
<a
|
||||
key={idx}
|
||||
href={project.url}
|
||||
onMouseEnter={() => setIsHovering(project.name)}
|
||||
onMouseLeave={() => setIsHovering(null)}
|
||||
className="group relative bg-white/5 backdrop-blur-md rounded-2xl p-8 border border-white/10 hover:border-purple-500/50 transition-all duration-300 hover:scale-105 hover:shadow-2xl hover:shadow-purple-500/20"
|
||||
>
|
||||
<div className="absolute inset-0 bg-gradient-to-br opacity-0 group-hover:opacity-10 rounded-2xl transition-opacity duration-300"
|
||||
style={{ background: `linear-gradient(135deg, rgb(168, 85, 247), rgb(147, 51, 234))` }} />
|
||||
|
||||
<div className="relative">
|
||||
<div className="flex items-start justify-between mb-4">
|
||||
<div className={`p-3 rounded-xl bg-gradient-to-br ${project.gradient} shadow-lg`}>
|
||||
<BookOpen className="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<span className="px-3 py-1 bg-emerald-500/20 text-emerald-300 rounded-full text-sm border border-emerald-500/30">
|
||||
{project.status}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl font-bold mb-3 group-hover:text-purple-300 transition-colors">
|
||||
{project.name}
|
||||
</h3>
|
||||
|
||||
<p className="text-gray-400 mb-4 leading-relaxed">
|
||||
{project.description}
|
||||
</p>
|
||||
|
||||
<div className="flex items-center text-purple-400 font-semibold group-hover:gap-3 gap-2 transition-all">
|
||||
Read docs
|
||||
<ChevronRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
|
||||
{/* Coming Soon Card */}
|
||||
<div className="relative bg-white/5 backdrop-blur-md rounded-2xl p-8 border border-dashed border-white/20">
|
||||
<div className="opacity-60">
|
||||
<div className="p-3 rounded-xl bg-gradient-to-br from-gray-600 to-gray-700 w-fit mb-4">
|
||||
<BookOpen className="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold mb-3 text-gray-400">More Projects</h3>
|
||||
<p className="text-gray-500 leading-relaxed">
|
||||
Additional documentation sites coming soon...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* External Links */}
|
||||
<section>
|
||||
<div className="flex items-center gap-3 mb-8">
|
||||
<Sparkles className="w-6 h-6 text-pink-400" />
|
||||
<h2 className="text-3xl font-bold">Explore More</h2>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{links.map((link, idx) => {
|
||||
const Icon = link.icon
|
||||
return (
|
||||
<a
|
||||
key={idx}
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="group bg-white/5 backdrop-blur-md rounded-2xl p-6 border border-white/10 hover:border-pink-500/50 transition-all duration-300 hover:scale-105 hover:shadow-2xl hover:shadow-pink-500/20 flex items-center gap-4"
|
||||
>
|
||||
<div className={`p-4 rounded-xl bg-gradient-to-br ${link.gradient} shadow-lg group-hover:scale-110 transition-transform`}>
|
||||
<Icon className="w-7 h-7 text-white" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-xl font-bold group-hover:text-pink-300 transition-colors">
|
||||
{link.title}
|
||||
</h3>
|
||||
<p className="text-gray-400 text-sm">{link.url}</p>
|
||||
</div>
|
||||
<ChevronRight className="w-6 h-6 text-gray-400 group-hover:text-pink-400 group-hover:translate-x-1 transition-all" />
|
||||
</a>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="mt-20 pt-8 border-t border-white/10 text-center text-gray-400">
|
||||
<p className="text-sm">
|
||||
Crafted with passion by <span className="text-purple-400 font-semibold">Valknar</span> ·
|
||||
<a href="http://pivoine.art" className="hover:text-purple-300 transition-colors ml-1">pivoine.art</a>
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user