Initial commit
This commit is contained in:
98
src/components/CallToAction.jsx
Normal file
98
src/components/CallToAction.jsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import { useState, useRef } from 'react';
|
||||
import { motion, useInView } from 'framer-motion';
|
||||
import joinusImg from '../assets/joinus.png';
|
||||
import SocietyTerminal from './SocietyTerminal';
|
||||
|
||||
const CallToAction = () => {
|
||||
const [showTerminal, setShowTerminal] = useState(false);
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true, margin: "-100px" });
|
||||
|
||||
const fadeInUp = {
|
||||
hidden: { opacity: 0, y: 50 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.6 } }
|
||||
};
|
||||
|
||||
const bounceIn = {
|
||||
hidden: { scale: 0, opacity: 0 },
|
||||
visible: { scale: 1, opacity: 1, transition: { type: "spring", bounce: 0.4, duration: 0.8 } }
|
||||
};
|
||||
|
||||
const staggerContainer = {
|
||||
visible: { transition: { staggerChildren: 0.3 } }
|
||||
};
|
||||
|
||||
return (
|
||||
<section ref={ref} className="section-padding bg-dark-gradient">
|
||||
<motion.div
|
||||
className="container-width text-center"
|
||||
initial="hidden"
|
||||
animate={isInView ? "visible" : "hidden"}
|
||||
variants={staggerContainer}
|
||||
>
|
||||
{/* Mascot */}
|
||||
<motion.div
|
||||
className="mb-8"
|
||||
variants={bounceIn}
|
||||
>
|
||||
<img
|
||||
src={joinusImg}
|
||||
alt="Mycelium Society Mascot"
|
||||
className="w-48 h-48 mx-auto rounded-full bg-gradient-to-br from-bright-cyan/20 to-cyan/20 p-4"
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
{/* Heading */}
|
||||
<motion.h2
|
||||
className="text-4xl md:text-5xl font-bold text-white mb-8"
|
||||
variants={fadeInUp}
|
||||
>
|
||||
Join as a Founding Member
|
||||
</motion.h2>
|
||||
|
||||
{/* Body Text */}
|
||||
<motion.p
|
||||
className="text-lg md:text-xl text-gray-300 leading-relaxed max-w-3xl mx-auto mb-12"
|
||||
variants={fadeInUp}
|
||||
>
|
||||
This is early days. Every founding member shapes what Mycelium Society becomes. We're shaping the future of digital sovereignty, together. Your participation matters. Your needs drive development. Your voice decides what we build next.
|
||||
</motion.p>
|
||||
|
||||
{/* CTA Button */}
|
||||
<motion.div variants={fadeInUp}>
|
||||
<motion.button
|
||||
className="btn-primary animate-pulse-glow text-lg px-8 py-4"
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
onClick={() => setShowTerminal(true)}
|
||||
animate={{
|
||||
boxShadow: [
|
||||
"0 0 5px #00d9ff",
|
||||
"0 0 20px #00d9ff, 0 0 30px #00d9ff",
|
||||
"0 0 5px #00d9ff"
|
||||
]
|
||||
}}
|
||||
transition={{
|
||||
boxShadow: {
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}
|
||||
}}
|
||||
>
|
||||
> Enter the Network
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{showTerminal && (
|
||||
<SocietyTerminal
|
||||
showTerminal={showTerminal}
|
||||
setShowTerminal={setShowTerminal}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default CallToAction;
|
69
src/components/CorePillars.jsx
Normal file
69
src/components/CorePillars.jsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { useInView } from 'framer-motion';
|
||||
import { useRef } from 'react';
|
||||
|
||||
const CorePillars = () => {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true, margin: "-100px" });
|
||||
|
||||
const slideInLeft = {
|
||||
hidden: { opacity: 0, x: -50 },
|
||||
visible: { opacity: 1, x: 0, transition: { duration: 0.6 } }
|
||||
};
|
||||
|
||||
const staggerContainer = {
|
||||
visible: { transition: { staggerChildren: 0.3 } }
|
||||
};
|
||||
|
||||
const pillars = [
|
||||
{
|
||||
title: "Sovereign Infrastructure",
|
||||
content: "We've already built the foundation: a decentralized cloud, peer-to-peer networking protocols, and a legally recognized digital free zone. Your infrastructure runs on systems you control, based on networks that can't be shut down."
|
||||
},
|
||||
{
|
||||
title: "Collective Direction",
|
||||
content: "Members use on-chain unmediated services to replace rent. Every layer matters. Every voice shapes our development roadmap. The tools you need become the tools we build."
|
||||
},
|
||||
{
|
||||
title: "Legal Framework",
|
||||
content: "This town isn't in a suitcase jurisdiction! We're a legally recognized legal framework. This isn't legal grey area. It's compliant, legitimate, and protected. Every service we build protects your sovereignty and helps individuals and firms handle compliance, manage taxation, all through integrated systems designed for digital sovereignty."
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section ref={ref} className="section-padding bg-dark-gradient">
|
||||
<motion.div
|
||||
className="container-width"
|
||||
initial="hidden"
|
||||
animate={isInView ? "visible" : "hidden"}
|
||||
variants={staggerContainer}
|
||||
>
|
||||
<motion.h2
|
||||
className="text-4xl md:text-5xl font-bold text-white mb-16 text-center"
|
||||
variants={slideInLeft}
|
||||
>
|
||||
Core Pillars
|
||||
</motion.h2>
|
||||
|
||||
<div className="space-y-12">
|
||||
{pillars.map((pillar, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
className="border-l-2 border-bright-cyan pl-6 py-4"
|
||||
variants={slideInLeft}
|
||||
>
|
||||
<h3 className="text-2xl md:text-3xl font-bold text-white mb-4">
|
||||
{pillar.title}
|
||||
</h3>
|
||||
<p className="text-lg text-gray-300 leading-relaxed">
|
||||
{pillar.content}
|
||||
</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default CorePillars;
|
53
src/components/ForYou.jsx
Normal file
53
src/components/ForYou.jsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { useInView } from 'framer-motion';
|
||||
import { useRef } from 'react';
|
||||
import ScrollingCards from './ScrollingCards';
|
||||
|
||||
const ForYou = () => {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true, margin: "-100px" });
|
||||
|
||||
const fadeInUp = {
|
||||
hidden: { opacity: 0, y: 50 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.6 } }
|
||||
};
|
||||
|
||||
const staggerContainer = {
|
||||
visible: { transition: { staggerChildren: 0.3 } }
|
||||
};
|
||||
|
||||
return (
|
||||
<section ref={ref} className="section-padding bg-dark-gradient">
|
||||
<motion.div
|
||||
className="w-full"
|
||||
initial="hidden"
|
||||
animate={isInView ? "visible" : "hidden"}
|
||||
variants={staggerContainer}
|
||||
>
|
||||
{/* Section Header */}
|
||||
<div className="container-width text-center mb-16">
|
||||
<motion.h2
|
||||
className="text-4xl md:text-5xl font-bold text-white mb-8"
|
||||
variants={fadeInUp}
|
||||
>
|
||||
For You
|
||||
</motion.h2>
|
||||
|
||||
<motion.p
|
||||
className="text-lg md:text-xl text-gray-300 leading-relaxed max-w-4xl mx-auto"
|
||||
variants={fadeInUp}
|
||||
>
|
||||
Mycelium Society is for those building the sovereign digital world. Whether you're launching decentralized networks, protecting user privacy, or creating new forms of online communities, our infrastructure gives you full control, no intermediaries, no limits.
|
||||
</motion.p>
|
||||
</div>
|
||||
|
||||
{/* Scrolling Cards */}
|
||||
<motion.div variants={fadeInUp}>
|
||||
<ScrollingCards />
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default ForYou;
|
131
src/components/Foundations.jsx
Normal file
131
src/components/Foundations.jsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import { useState } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
|
||||
import legal from '../assets/legal.png';
|
||||
import collective from '../assets/collective.png';
|
||||
import sovereign from '../assets/sovereign.png';
|
||||
|
||||
const Foundations = () => {
|
||||
|
||||
|
||||
const [activeImage, setActiveImage] = useState(legal);
|
||||
const [hoveredIndex, setHoveredIndex] = useState(0); // Start with first item highlighted
|
||||
|
||||
const foundations = [
|
||||
{
|
||||
title: 'Legal Framework',
|
||||
line1: 'Operate as a sovereign legal entity within our digital free zone. Form businesses, manage compliance, and handle taxation, all within a transparent, compliant system designed for digital sovereignty.',
|
||||
image: legal,
|
||||
},
|
||||
{
|
||||
title: 'Collective Direction',
|
||||
line1: 'Members guide the roadmap. Every voice counts, every vote matters.',
|
||||
line2: 'Together, we decide which tools replace corporate dependencies.',
|
||||
image: collective,
|
||||
},
|
||||
{
|
||||
title: 'Sovereign Infrastructure',
|
||||
line1: 'A decentralized cloud, peer-to-peer networking protocols, and a legally recognized digital free zone. Your systems, your control, hosted on networks that cannot be shut down.',
|
||||
image: sovereign,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="bg-gradient-to-b from-gray-900 to-black py-20 text-white">
|
||||
<div className="max-w-7xl mx-auto px-6">
|
||||
{/* Header */}
|
||||
<div className="mb-16 text-center">
|
||||
<h2 className="text-5xl font-bold text-center">
|
||||
The <span className="text-cyan-400">Foundations</span> of the
|
||||
</h2>
|
||||
<h2 className="text-5xl font-bold text-center">Mycelium Society</h2>
|
||||
</div>
|
||||
|
||||
{/* Two Column Container - Using Inline Styles for Absolute Control */}
|
||||
<div style={{ display: 'flex', flexDirection: 'row', gap: '6rem', alignItems: 'center', justifyContent: 'center' }} className="flex-col lg:flex-row">
|
||||
{/* Left Column - Image */}
|
||||
<div style={{ width: '280px', flexShrink: 0 }} className="w-full lg:w-auto mb-12 lg:mb-0">
|
||||
<div className="lg:sticky lg:top-24">
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.img
|
||||
key={activeImage}
|
||||
src={activeImage}
|
||||
alt="Foundation illustration"
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.9 }}
|
||||
transition={{ duration: 0.4, ease: [0.4, 0, 0.2, 1] }}
|
||||
style={{ width: '100%', height: 'auto', display: 'block' }}
|
||||
/>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column - Text Content */}
|
||||
<div style={{ flex: 1, minWidth: 0, maxWidth: '60ch' }} className="w-full">
|
||||
<div className="space-y-8">
|
||||
{foundations.map((foundation, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
onMouseEnter={() => {
|
||||
setActiveImage(foundation.image);
|
||||
setHoveredIndex(index);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setActiveImage(mushroom);
|
||||
setHoveredIndex(null);
|
||||
}}
|
||||
className="relative group cursor-pointer"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
>
|
||||
<div className={`
|
||||
p-6 pb-8 rounded-lg transition-all duration-300 text-center
|
||||
${hoveredIndex === index
|
||||
? 'bg-gray-800/50 backdrop-blur-sm'
|
||||
: 'bg-transparent'
|
||||
}
|
||||
`}>
|
||||
<motion.div
|
||||
className="absolute left-0 top-0 bottom-0 w-1 bg-cyan-400"
|
||||
initial={{ scaleY: 0 }}
|
||||
animate={{ scaleY: hoveredIndex === index ? 1 : 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
/>
|
||||
|
||||
<h3 className={`
|
||||
text-2xl lg:text-3xl font-bold mb-2 transition-colors duration-300
|
||||
${hoveredIndex === index ? 'text-cyan-400' : 'text-white'}
|
||||
`}>
|
||||
{foundation.title}
|
||||
</h3>
|
||||
|
||||
<p className={`
|
||||
text-base lg:text-lg leading-relaxed transition-all duration-300
|
||||
${hoveredIndex === index ? 'text-gray-100' : 'text-gray-400'}
|
||||
`}>
|
||||
{foundation.line1}
|
||||
</p>
|
||||
<p className={`
|
||||
text-base lg:text-lg leading-relaxed transition-all duration-300 mt-2 mb-12
|
||||
${hoveredIndex === index ? 'text-gray-100' : 'text-gray-400'}
|
||||
`}>
|
||||
{foundation.line2}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{index < foundations.length - 1 && (
|
||||
<div className="mt-6 h-px bg-gradient-to-r from-gray-700 via-gray-600 to-transparent" />
|
||||
)}
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Foundations;
|
107
src/components/Hero.jsx
Normal file
107
src/components/Hero.jsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import mushroomImg from '../assets/mushroom.png';
|
||||
import SocietyTerminal from './SocietyTerminal';
|
||||
|
||||
const Hero = () => {
|
||||
const [showTerminal, setShowTerminal] = useState(false);
|
||||
|
||||
const fadeInUp = {
|
||||
hidden: { opacity: 0, y: 50 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.6 } }
|
||||
};
|
||||
|
||||
const bounceIn = {
|
||||
hidden: { scale: 0, opacity: 0 },
|
||||
visible: { scale: 1, opacity: 1, transition: { type: "spring", bounce: 0.4, duration: 0.8 } }
|
||||
};
|
||||
|
||||
const staggerContainer = {
|
||||
visible: { transition: { staggerChildren: 0.2 } }
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="min-h-screen flex items-center justify-center bg-dark-gradient relative overflow-hidden">
|
||||
<motion.div
|
||||
className="text-center z-10"
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
variants={staggerContainer}
|
||||
>
|
||||
{/* Mascot */}
|
||||
<motion.div
|
||||
className="mb-8"
|
||||
variants={bounceIn}
|
||||
>
|
||||
<img
|
||||
src={mushroomImg}
|
||||
alt="Mycelium Society Mascot"
|
||||
className="mx-auto max-w-xs"
|
||||
style={{ width: 'auto', height: 'auto', maxHeight: '300px' }}
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
{/* Main Title */}
|
||||
<motion.h1
|
||||
className="text-4xl md:text-6xl lg:text-7xl font-bold mb-8 leading-tight"
|
||||
variants={fadeInUp}
|
||||
>
|
||||
<span className="text-white">Welcome to</span>
|
||||
<br />
|
||||
<span className="text-bright-cyan">Mycelium Society</span>
|
||||
</motion.h1>
|
||||
|
||||
{/* Tagline */}
|
||||
<motion.p
|
||||
className="text-lg md:text-xl text-gray-300 mb-12 max-w-3xl mx-auto"
|
||||
variants={fadeInUp}
|
||||
>
|
||||
A community inspired by network state concepts, combining people,
|
||||
<br className="hidden sm:block" />
|
||||
technology, and governance for global collaboration.
|
||||
</motion.p>
|
||||
|
||||
{/* Buttons */}
|
||||
<motion.div
|
||||
className="flex flex-col sm:flex-row gap-4 justify-center items-center"
|
||||
variants={fadeInUp}
|
||||
>
|
||||
<motion.button
|
||||
className="btn-primary animate-pulse-glow"
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
onClick={() => setShowTerminal(true)}
|
||||
>
|
||||
> ENTER THE NETWORK
|
||||
</motion.button>
|
||||
<a href="https://docs.ourworld.tf/mycelium_society_docs/docs/" target="_blank" rel="noopener noreferrer">
|
||||
<motion.button
|
||||
className="btn-primary"
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
> LEARN MORE
|
||||
</motion.button>
|
||||
</a>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
{/* Background Effects */}
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<div className="absolute -top-40 -right-40 w-80 h-80 bg-bright-cyan/5 rounded-full blur-3xl"></div>
|
||||
<div className="absolute -bottom-40 -left-40 w-80 h-80 bg-cyan/5 rounded-full blur-3xl"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{showTerminal && (
|
||||
<SocietyTerminal
|
||||
showTerminal={showTerminal}
|
||||
setShowTerminal={setShowTerminal}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Hero;
|
52
src/components/Manifesto.jsx
Normal file
52
src/components/Manifesto.jsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import manifest from '../assets/manifest.png';
|
||||
|
||||
const Manifesto = () => {
|
||||
|
||||
return (
|
||||
<section className="bg-gradient-to-b from-gray-900 to-black py-20 text-white">
|
||||
<div className="max-w-7xl mx-auto px-6">
|
||||
{/* Header */}
|
||||
<div className="mb-16 text-center">
|
||||
<h2 className="text-5xl font-bold text-center">
|
||||
Our <span className="text-cyan-400">Manifesto</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* Two Column Container - Using Inline Styles for Absolute Control */}
|
||||
<div style={{ display: 'flex', flexDirection: 'row', gap: '6rem', alignItems: 'flex-start', justifyContent: 'center' }} className="flex-col lg:flex-row">
|
||||
{/* Left Column - Image */}
|
||||
<div style={{ width: '280px', flexShrink: 0 }} className="w-full lg:w-auto mb-12 lg:mb-0">
|
||||
<div className="lg:sticky lg:top-24">
|
||||
<img
|
||||
src={manifest}
|
||||
alt="Mycelium Society Mascot"
|
||||
style={{ width: '100%', height: 'auto', display: 'block' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column - Text Content */}
|
||||
<div style={{ flex: 1, minWidth: 0, maxWidth: '60ch' }} className="w-full">
|
||||
<div className="space-y-8">
|
||||
<p className="text-lg md:text-xl leading-relaxed text-gray-300 text-center">
|
||||
Mycelium Society's mission is to eventually provide every tool individuals, organizations, and network states need to strategically opt-out of centralized digital systems and thrive independently with sovereign legal standing.
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<div className="pt-4 text-center">
|
||||
<p className="text-lg md:text-xl font-bold">
|
||||
Own your digital sovereignty.
|
||||
</p>
|
||||
<p className="text-lg md:text-xl font-bold text-cyan-400">
|
||||
Legally. Transparently. Together.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Manifesto;
|
121
src/components/ScrollingCards.jsx
Normal file
121
src/components/ScrollingCards.jsx
Normal file
@@ -0,0 +1,121 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import builderImg from '../assets/builder.png';
|
||||
import privacyAdvocateImg from '../assets/privacy_advocate.png';
|
||||
import nomadImg from '../assets/nomad.png';
|
||||
import creatorImg from '../assets/creator.png';
|
||||
import developerImg from '../assets/developer.png';
|
||||
import communityImg from '../assets/community.png';
|
||||
import mushroomImg from '../assets/mushroom.png';
|
||||
|
||||
const ScrollingCards = () => {
|
||||
const cards = [
|
||||
|
||||
{
|
||||
title: "For Privacy Seekers",
|
||||
text: "Use digital tools that respect your data and autonomy by design, not as an afterthought.",
|
||||
image: privacyAdvocateImg
|
||||
},
|
||||
{
|
||||
title: "For Digital Nomads",
|
||||
text: "Manage your finances and business operations with a sovereign infrastructure that's always with you.",
|
||||
image: nomadImg
|
||||
},
|
||||
{
|
||||
title: "For Creators",
|
||||
text: "Own your content and distribution channels without platform intermediaries.",
|
||||
image: creatorImg
|
||||
},
|
||||
{
|
||||
title: "For Developers",
|
||||
text: "Access full-stack decentralized infrastructure to build your sovereign digital foundation, from secure UIs to robust legal frameworks.",
|
||||
image: developerImg
|
||||
},
|
||||
|
||||
{
|
||||
title: "For Organizations",
|
||||
text: "Deploy private open source collaboration stacks, keeping your sensitive information within your own infrastructure.",
|
||||
image: communityImg
|
||||
},
|
||||
{
|
||||
title: "For Network States",
|
||||
text: "Access full-stack decentralized infrastructure to build your sovereign digital foundation.",
|
||||
image: builderImg
|
||||
}
|
||||
];
|
||||
|
||||
// Duplicate cards for seamless infinite scroll
|
||||
const duplicatedCards = [...cards, ...cards];
|
||||
|
||||
return (
|
||||
<div style={{ overflow: 'hidden', padding: '2rem 0' }}>
|
||||
<motion.div
|
||||
style={{
|
||||
display: 'flex',
|
||||
gap: '1.5rem',
|
||||
width: `${(cards.length * 2) * 300}px`
|
||||
}}
|
||||
animate={{
|
||||
x: [0, -(cards.length * 300)]
|
||||
}}
|
||||
transition={{
|
||||
x: {
|
||||
repeat: Infinity,
|
||||
repeatType: "loop",
|
||||
duration: 35,
|
||||
ease: "linear",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{duplicatedCards.map((card, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
flexShrink: 0,
|
||||
width: '280px',
|
||||
}}
|
||||
>
|
||||
{/* Top section with mascot */}
|
||||
<div style={{
|
||||
height: '280px',
|
||||
overflow: 'hidden',
|
||||
borderRadius: '16px',
|
||||
boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
|
||||
}}>
|
||||
<img
|
||||
src={card.image}
|
||||
alt={card.title}
|
||||
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Bottom section with text */}
|
||||
<div style={{
|
||||
padding: '1rem 0',
|
||||
textAlign: 'center'
|
||||
}}>
|
||||
<h3 style={{
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.125rem',
|
||||
marginBottom: '0.5rem',
|
||||
fontFamily: "'Roboto Mono', monospace"
|
||||
}}>
|
||||
{card.title}
|
||||
</h3>
|
||||
<p style={{
|
||||
color: '#9ca3af',
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: '1.4',
|
||||
fontFamily: "'Roboto Mono', monospace"
|
||||
}}>
|
||||
{card.text}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScrollingCards;
|
58
src/components/SocietyTerminal.jsx
Normal file
58
src/components/SocietyTerminal.jsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
function SocietyTerminal({ showTerminal, setShowTerminal }) {
|
||||
const [terminalText, setTerminalText] = useState('');
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
|
||||
const redirectMessages = [
|
||||
'> connecting to member portal...',
|
||||
'> synchronizing with mycelium network...',
|
||||
'> welcome, initiate...'
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
let typingTimer;
|
||||
|
||||
if (showTerminal) {
|
||||
if (currentStep < redirectMessages.length) {
|
||||
if (terminalText !== redirectMessages[currentStep]) {
|
||||
typingTimer = setTimeout(() => {
|
||||
setTerminalText(redirectMessages[currentStep].substring(0, terminalText.length + 1));
|
||||
}, 50);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
setCurrentStep(currentStep + 1);
|
||||
}, 1000);
|
||||
}
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
window.location.href = 'https://docs.ourworld.tf/mycelium_society_docs/docs/';
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
return () => clearTimeout(typingTimer);
|
||||
}, [showTerminal, currentStep, terminalText]);
|
||||
|
||||
return (
|
||||
<div className="terminal-overlay">
|
||||
<div className="terminal">
|
||||
<div className="terminal-header">
|
||||
<div className="terminal-title">MYCELIUM SOCIETY PORTAL</div>
|
||||
<button className="terminal-close" onClick={() => setShowTerminal(false)}>
|
||||
abort
|
||||
</button>
|
||||
</div>
|
||||
<div className="terminal-body h-96">
|
||||
<div id="terminal-content">
|
||||
{terminalText}
|
||||
<span className="terminal-cursor"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SocietyTerminal;
|
47
src/components/ui/button.jsx
Normal file
47
src/components/ui/button.jsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva } from "class-variance-authority";
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 rounded-md px-3",
|
||||
lg: "h-11 rounded-md px-8",
|
||||
icon: "h-10 w-10",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
return (
|
||||
(<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props} />)
|
||||
);
|
||||
})
|
||||
Button.displayName = "Button"
|
||||
|
||||
export { Button, buttonVariants }
|
Reference in New Issue
Block a user