3d-blogiverse / script.js
MAWB's picture
fix the header of the website
06d89a6 verified
// Main Application Script
document.addEventListener('DOMContentLoaded', function() {
// Initialize Three.js Scene
initThreeJSScene();
initInteractive3DScene();
// Load Blog Posts from API
loadBlogPosts();
// Theme Toggle Logic
initThemeToggle();
// Smooth Scroll for Anchor Links
initSmoothScroll();
// Initialize CMS Dashboard Demo
initCMSDashboard();
});
// Three.js Background Animation
function initThreeJSScene() {
const container = document.getElementById('threejs-container');
if (!container) return;
// Scene setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(container.clientWidth, container.clientHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
container.appendChild(renderer.domElement);
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(5, 5, 5);
scene.add(directionalLight);
// Create floating geometric objects
const geometryTypes = [
new THREE.TorusGeometry(1, 0.4, 16, 100),
new THREE.IcosahedronGeometry(1, 0),
new THREE.OctahedronGeometry(1, 0),
new THREE.TorusKnotGeometry(1, 0.3, 100, 16)
];
const material = new THREE.MeshStandardMaterial({
color: 0x3b82f6,
metalness: 0.3,
roughness: 0.4,
transparent: true,
opacity: 0.8
});
const objects = [];
for (let i = 0; i < 8; i++) {
const geometry = geometryTypes[Math.floor(Math.random() * geometryTypes.length)];
const mesh = new THREE.Mesh(geometry, material.clone());
mesh.position.x = (Math.random() - 0.5) * 20;
mesh.position.y = (Math.random() - 0.5) * 10;
mesh.position.z = (Math.random() - 0.5) * 20;
mesh.rotation.x = Math.random() * Math.PI;
mesh.rotation.y = Math.random() * Math.PI;
mesh.userData = {
speed: 0.02 + Math.random() * 0.03,
rotationSpeed: {
x: (Math.random() - 0.5) * 0.02,
y: (Math.random() - 0.5) * 0.02,
z: (Math.random() - 0.5) * 0.02
},
floatAmplitude: 0.5 + Math.random() * 1,
floatSpeed: 1 + Math.random() * 2,
initialY: mesh.position.y
};
mesh.material.color.setHSL(Math.random(), 0.7, 0.6);
scene.add(mesh);
objects.push(mesh);
}
camera.position.z = 15;
// Animation loop
function animate() {
requestAnimationFrame(animate);
objects.forEach(mesh => {
// Floating animation
mesh.position.y = mesh.userData.initialY + Math.sin(Date.now() * 0.001 * mesh.userData.floatSpeed) * mesh.userData.floatAmplitude;
// Rotation
mesh.rotation.x += mesh.userData.rotationSpeed.x;
mesh.rotation.y += mesh.userData.rotationSpeed.y;
mesh.rotation.z += mesh.userData.rotationSpeed.z;
// Gentle orbit
mesh.position.x += Math.cos(Date.now() * 0.001 * mesh.userData.speed) * 0.02;
mesh.position.z += Math.sin(Date.now() * 0.001 * mesh.userData.speed) * 0.02;
});
renderer.render(scene, camera);
}
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = container.clientWidth / container.clientHeight;
camera.updateProjectionMatrix();
renderer.setSize(container.clientWidth, container.clientHeight);
});
animate();
}
// Interactive 3D Scene
function initInteractive3DScene() {
const container = document.getElementById('interactive-3d');
if (!container) return;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(container.clientWidth, container.clientHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
container.appendChild(renderer.domElement);
// Add OrbitControls
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Create a more complex 3D object
const geometry = new THREE.IcosahedronGeometry(3, 2);
const material = new THREE.MeshNormalMaterial({ wireframe: false });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// Add wireframe version
const wireframe = new THREE.LineSegments(
new THREE.WireframeGeometry(geometry),
new THREE.LineBasicMaterial({ color: 0xffffff, linewidth: 2 })
);
mesh.add(wireframe);
// Add particles around the object
const particleGeometry = new THREE.BufferGeometry();
const particleCount = 1000;
const positions = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount * 3; i += 3) {
const radius = 5 + Math.random() * 3;
const theta = Math.random() * Math.PI * 2;
const phi = Math.random() * Math.PI;
positions[i] = radius * Math.sin(phi) * Math.cos(theta);
positions[i + 1] = radius * Math.cos(phi);
positions[i + 2] = radius * Math.sin(phi) * Math.sin(theta);
}
particleGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
const particleMaterial = new THREE.PointsMaterial({
color: 0xa855f7,
size: 0.05,
transparent: true
});
const particles = new THREE.Points(particleGeometry, particleMaterial);
scene.add(particles);
camera.position.z = 10;
// Animation loop
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.005;
particles.rotation.y += 0.001;
controls.update();
renderer.render(scene, camera);
}
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = container.clientWidth / container.clientHeight;
camera.updateProjectionMatrix();
renderer.setSize(container.clientWidth, container.clientHeight);
});
animate();
}
// Load Blog Posts from Mock API
async function loadBlogPosts() {
const container = document.getElementById('blog-posts');
if (!container) return;
// Mock API URL - In a real implementation, this would be your headless CMS endpoint
const mockApiUrl = 'https://jsonplaceholder.typicode.com/posts?_limit=6';
try {
container.innerHTML = `
<div class="col-span-1 md:col-span-2 lg:col-span-3 text-center py-12">
<div class="inline-block animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary-600"></div>
<p class="mt-4 text-gray-600 dark:text-gray-400">Loading articles from CMS...</p>
</div>
`;
const response = await fetch(mockApiUrl);
const posts = await response.json();
container.innerHTML = '';
posts.forEach((post, index) => {
const colors = ['primary', 'secondary'];
const color = colors[index % colors.length];
const card = document.createElement('div');
card.className = 'blog-card bg-white dark:bg-gray-800 rounded-2xl shadow-xl overflow-hidden transform transition-all duration-300 hover:shadow-2xl';
card.innerHTML = `
<div class="h-48 overflow-hidden">
<img src="https://static.photos/${color === 'primary' ? 'technology' : 'abstract'}/640x360/${index + 100}"
alt="${post.title}"
class="w-full h-full object-cover transform hover:scale-110 transition-transform duration-500">
</div>
<div class="p-6">
<div class="flex items-center gap-2 mb-4">
<span class="px-3 py-1 text-xs font-semibold rounded-full bg-${color}-100 dark:bg-${color}-900/30 text-${color}-600 dark:text-${color}-400">
${color === 'primary' ? 'TECHNOLOGY' : 'DESIGN'}
</span>
<span class="text-gray-500 dark:text-gray-400 text-sm">${Math.floor(Math.random() * 30) + 1} min read</span>
</div>
<h3 class="text-xl font-bold mb-3 line-clamp-2">${post.title}</h3>
<p class="text-gray-600 dark:text-gray-400 mb-4 line-clamp-3">${post.body}</p>
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<div class="w-8 h-8 rounded-full bg-gradient-to-r from-${color}-400 to-${color}-600 flex items-center justify-center text-white text-xs">
${post.userId}
</div>
<span class="text-sm text-gray-700 dark:text-gray-300">Author ${post.userId}</span>
</div>
<a href="#" class="text-${color}-600 dark:text-${color}-400 hover:text-${color}-700 dark:hover:text-${color}-300 font-semibold text-sm flex items-center gap-1">
Read More <i data-feather="arrow-right" class="w-4 h-4"></i>
</a>
</div>
</div>
`;
container.appendChild(card);
});
feather.replace();
} catch (error) {
console.error('Error loading blog posts:', error);
container.innerHTML = `
<div class="col-span-1 md:col-span-2 lg:col-span-3 text-center py-12">
<i data-feather="alert-circle" class="w-16 h-16 text-red-500 mx-auto"></i>
<p class="mt-4 text-gray-600 dark:text-gray-400">Unable to load articles. Please check your connection.</p>
</div>
`;
feather.replace();
}
}
// Theme Toggle Functionality
function initThemeToggle() {
const themeToggles = document.querySelectorAll('[data-theme-toggle]');
if (!themeToggles.length) return;
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
const currentTheme = localStorage.getItem('theme') || (prefersDarkScheme.matches ? 'dark' : 'light');
if (currentTheme === 'dark') {
document.documentElement.classList.add('dark');
}
themeToggles.forEach(themeToggle => {
themeToggle.addEventListener('click', () => {
const isDark = document.documentElement.classList.toggle('dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
// Update icons
const icons = document.querySelectorAll('[data-feather]');
icons.forEach(icon => {
if (icon.getAttribute('data-feather') === 'moon' || icon.getAttribute('data-feather') === 'sun') {
icon.setAttribute('data-feather', isDark ? 'sun' : 'moon');
}
});
feather.replace();
});
});
// Also update icons on initial load
setTimeout(() => {
const isDark = document.documentElement.classList.contains('dark');
const icons = document.querySelectorAll('[data-feather]');
icons.forEach(icon => {
if (icon.getAttribute('data-feather') === 'moon' || icon.getAttribute('data-feather') === 'sun') {
icon.setAttribute('data-feather', isDark ? 'sun' : 'moon');
}
});
feather.replace();
}, 100);
}
// Smooth Scroll Implementation
function initSmoothScroll() {
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
if (targetId === '#') return;
const targetElement = document.querySelector(targetId);
if (targetElement) {
window.scrollTo({
top: targetElement.offsetTop - 80,
behavior: 'smooth'
});
}
});
});
}
// CMS Dashboard Demo
function initCMSDashboard() {
// Simulate real-time updates
setInterval(() => {
const stats = document.querySelectorAll('.stat-value');
stats.forEach(stat => {
if (stat.classList.contains('animate-pulse')) {
stat.classList.remove('animate-pulse');
setTimeout(() => stat.classList.add('animate-pulse'), 10);
}
});
}, 3000);
// Simulate API call for CMS status
setTimeout(() => {
const statusIndicator = document.getElementById('cms-status');
if (statusIndicator) {
statusIndicator.innerHTML = `
<div class="flex items-center gap-2 text-green-500">
<div class="w-3 h-3 bg-green-500 rounded-full animate-pulse"></div>
<span>CMS Connected • Real-time Sync Active</span>
</div>
`;
}
}, 1500);
}