Add src/App.tsx
This commit is contained in:
parent
4918719836
commit
05282f923b
1 changed files with 894 additions and 0 deletions
894
src/App.tsx
Normal file
894
src/App.tsx
Normal file
|
|
@ -0,0 +1,894 @@
|
|||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import {
|
||||
Layers,
|
||||
Cpu,
|
||||
Boxes,
|
||||
Database,
|
||||
ArrowRight,
|
||||
ShieldCheck,
|
||||
CheckCircle,
|
||||
FileCode,
|
||||
Download,
|
||||
Copy,
|
||||
ExternalLink,
|
||||
ChevronRight,
|
||||
Sparkles,
|
||||
Terminal,
|
||||
Activity,
|
||||
Workflow,
|
||||
Globe,
|
||||
Settings,
|
||||
FolderGit2,
|
||||
Code2
|
||||
} from 'lucide-react';
|
||||
|
||||
export default function App() {
|
||||
const [activeTab, setActiveTab] = useState<'preview' | 'files' | 'architecture' | 'guide'>('preview');
|
||||
const [activePage, setActivePage] = useState<'home' | 'services' | 'odoo' | 'portfolio' | 'about' | 'contact'>('home');
|
||||
const [selectedFile, setSelectedFile] = useState<string>('__manifest__.py');
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [particleDensity, setParticleDensity] = useState<'low' | 'normal' | 'high'>('normal');
|
||||
|
||||
// Interactive 3D Canvas in Preview
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
let animationId: number;
|
||||
let width = (canvas.width = canvas.parentElement?.clientWidth || 800);
|
||||
let height = (canvas.height = canvas.parentElement?.clientHeight || 450);
|
||||
|
||||
const handleResize = () => {
|
||||
if (!canvas.parentElement) return;
|
||||
width = canvas.width = canvas.parentElement.clientWidth;
|
||||
height = canvas.height = canvas.parentElement.clientHeight;
|
||||
};
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
const count = particleDensity === 'low' ? 30 : particleDensity === 'high' ? 85 : 55;
|
||||
const particles: { x: number; y: number; vx: number; vy: number; radius: number }[] = [];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
particles.push({
|
||||
x: Math.random() * width,
|
||||
y: Math.random() * height,
|
||||
vx: (Math.random() - 0.5) * 0.8,
|
||||
vy: (Math.random() - 0.5) * 0.8,
|
||||
radius: Math.random() * 2 + 1.5,
|
||||
});
|
||||
}
|
||||
|
||||
let mouseX = width / 2;
|
||||
let mouseY = height / 2;
|
||||
|
||||
const onMouseMove = (e: MouseEvent) => {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
mouseX = e.clientX - rect.left;
|
||||
mouseY = e.clientY - rect.top;
|
||||
};
|
||||
canvas.addEventListener('mousemove', onMouseMove);
|
||||
|
||||
const render = () => {
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
// Draw subtle grid
|
||||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.03)';
|
||||
ctx.lineWidth = 1;
|
||||
const gridSize = 40;
|
||||
for (let x = 0; x < width; x += gridSize) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, 0);
|
||||
ctx.lineTo(x, height);
|
||||
ctx.stroke();
|
||||
}
|
||||
for (let y = 0; y < height; y += gridSize) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, y);
|
||||
ctx.lineTo(width, y);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Draw connections
|
||||
for (let i = 0; i < particles.length; i++) {
|
||||
const p1 = particles[i];
|
||||
p1.x += p1.vx;
|
||||
p1.y += p1.vy;
|
||||
|
||||
if (p1.x < 0 || p1.x > width) p1.vx *= -1;
|
||||
if (p1.y < 0 || p1.y > height) p1.vy *= -1;
|
||||
|
||||
// Draw particle
|
||||
ctx.beginPath();
|
||||
ctx.arc(p1.x, p1.y, p1.radius, 0, Math.PI * 2);
|
||||
ctx.fillStyle = '#00f2fe';
|
||||
ctx.shadowBlur = 8;
|
||||
ctx.shadowColor = 'rgba(0, 242, 254, 0.6)';
|
||||
ctx.fill();
|
||||
|
||||
for (let j = i + 1; j < particles.length; j++) {
|
||||
const p2 = particles[j];
|
||||
const dist = Math.hypot(p1.x - p2.x, p1.y - p2.y);
|
||||
if (dist < 110) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(p1.x, p1.y);
|
||||
ctx.lineTo(p2.x, p2.y);
|
||||
ctx.strokeStyle = `rgba(0, 242, 254, ${1 - dist / 110 * 0.7})`;
|
||||
ctx.lineWidth = 0.8;
|
||||
ctx.shadowBlur = 0;
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
animationId = requestAnimationFrame(render);
|
||||
};
|
||||
|
||||
render();
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(animationId);
|
||||
window.removeEventListener('resize', handleResize);
|
||||
canvas.removeEventListener('mousemove', onMouseMove);
|
||||
};
|
||||
}, [particleDensity, activePage]);
|
||||
|
||||
const fileManifest: Record<string, { path: string; lang: string; desc: string; code: string }> = {
|
||||
'__manifest__.py': {
|
||||
path: 'theme_3d_systems/__manifest__.py',
|
||||
lang: 'python',
|
||||
desc: 'Odoo 19 theme definition with dependency declarations, XML views & ES6 asset bundles',
|
||||
code: `# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': 'Theme 3D Systems',
|
||||
'summary': 'Futuristic 3D Website Theme for Web Systems, Odoo ERP Solutions & Software Engineering Companies',
|
||||
'category': 'Theme/Corporate',
|
||||
'version': '19.0.1.0.0',
|
||||
'license': 'LGPL-3',
|
||||
'depends': [
|
||||
'website',
|
||||
'website_crm',
|
||||
'website_mass_mailing',
|
||||
'web_editor',
|
||||
],
|
||||
'data': [
|
||||
'data/presets.xml',
|
||||
'data/menu.xml',
|
||||
'data/pages.xml',
|
||||
'views/layout.xml',
|
||||
'views/header.xml',
|
||||
'views/footer.xml',
|
||||
'views/snippets/snippets.xml',
|
||||
'views/snippets/options.xml',
|
||||
'views/snippets/s_3d_hero.xml',
|
||||
'views/snippets/s_system_architecture.xml',
|
||||
'views/snippets/s_floating_cards.xml',
|
||||
'views/snippets/s_odoo_modules_grid.xml',
|
||||
'views/snippets/s_portfolio_showcase.xml',
|
||||
'views/snippets/s_stats_matrix.xml',
|
||||
'views/snippets/s_tech_stack.xml',
|
||||
'views/snippets/s_testimonials_3d.xml',
|
||||
'views/snippets/s_cta_glow.xml',
|
||||
'views/pages/page_home.xml',
|
||||
'views/pages/page_services.xml',
|
||||
'views/pages/page_odoo_solutions.xml',
|
||||
'views/pages/page_portfolio.xml',
|
||||
'views/pages/page_about.xml',
|
||||
'views/pages/page_contact.xml',
|
||||
],
|
||||
'assets': {
|
||||
'web.assets_frontend': [
|
||||
'theme_3d_systems/static/src/scss/_variables.scss',
|
||||
'theme_3d_systems/static/src/scss/_mixins.scss',
|
||||
'theme_3d_systems/static/src/scss/theme.scss',
|
||||
'theme_3d_systems/static/src/scss/components.scss',
|
||||
'theme_3d_systems/static/src/scss/animations.scss',
|
||||
'theme_3d_systems/static/src/scss/snippets.scss',
|
||||
'theme_3d_systems/static/src/js/three/three_core_loader.js',
|
||||
'theme_3d_systems/static/src/js/three/hero_network_scene.js',
|
||||
'theme_3d_systems/static/src/js/widgets/widget_3d_hero.js',
|
||||
'theme_3d_systems/static/src/js/widgets/widget_card_tilt.js',
|
||||
'theme_3d_systems/static/src/js/widgets/widget_system_arch.js',
|
||||
'theme_3d_systems/static/src/js/widgets/widget_stats_counter.js',
|
||||
],
|
||||
'website.assets_editor': [
|
||||
'theme_3d_systems/static/src/js/options/snippet_3d_options.js',
|
||||
],
|
||||
},
|
||||
'installable': True,
|
||||
'application': False,
|
||||
}`
|
||||
},
|
||||
's_3d_hero.xml': {
|
||||
path: 'theme_3d_systems/views/snippets/s_3d_hero.xml',
|
||||
lang: 'xml',
|
||||
desc: 'Editable Three.js 3D Hero Snippet with standard oe_structure blocks',
|
||||
code: `<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="s_3d_hero" name="3D Interactive Hero">
|
||||
<section class="s_3d_hero position-relative py-5 py-lg-6" data-particle-density="normal">
|
||||
<!-- Three.js Canvas Injection Container -->
|
||||
<div class="hero-canvas-container"></div>
|
||||
|
||||
<div class="container position-relative z-index-2">
|
||||
<div class="row align-items-center min-vh-75">
|
||||
<div class="col-lg-8 col-xl-7 hero-content-wrapper">
|
||||
<div class="oe_structure">
|
||||
<span class="badge-tech-tag mb-3">
|
||||
<span class="status-pulse-dot"></span> Next-Gen Web Systems & ERP
|
||||
</span>
|
||||
</div>
|
||||
<div class="oe_structure">
|
||||
<h1 class="display-3 fw-bold text-white mb-4">
|
||||
Architecting <span class="text-gradient-cyan">Intelligent Systems</span> For High-Growth Enterprises
|
||||
</h1>
|
||||
</div>
|
||||
<div class="oe_structure">
|
||||
<p class="hero-lead mb-5 text-light-muted">
|
||||
We design and engineer scalable custom web architectures, seamless Odoo ERP ecosystems, and end-to-end automated business pipelines.
|
||||
</p>
|
||||
</div>
|
||||
<div class="oe_structure">
|
||||
<div class="d-flex flex-wrap gap-3 align-items-center">
|
||||
<a href="/services" class="btn btn-gradient-primary btn-lg shadow-glow">
|
||||
<span>Explore Our Solutions</span>
|
||||
<i class="fa fa-arrow-right ms-2"></i>
|
||||
</a>
|
||||
<a href="/contactus" class="btn btn-outline-cyber btn-lg">
|
||||
<span>Start Your Project</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
</odoo>`
|
||||
},
|
||||
'widget_3d_hero.js': {
|
||||
path: 'theme_3d_systems/static/src/js/widgets/widget_3d_hero.js',
|
||||
lang: 'javascript',
|
||||
desc: 'Odoo 19 PublicWidget for lazy-loading WebGL, memory cleanup, and Website Builder support',
|
||||
code: `/** @odoo-module **/
|
||||
|
||||
import publicWidget from '@web/legacy/js/public/public_widget';
|
||||
import { HeroNetworkScene } from '../three/hero_network_scene';
|
||||
|
||||
publicWidget.registry.Theme3DHero = publicWidget.Widget.extend({
|
||||
selector: '.s_3d_hero',
|
||||
disabledInEditableMode: false,
|
||||
|
||||
start: function () {
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
if (prefersReducedMotion) return;
|
||||
|
||||
const container = this.el.querySelector('.hero-canvas-container');
|
||||
if (container) {
|
||||
const density = this.el.dataset.particleDensity || 'normal';
|
||||
let count = 65;
|
||||
if (density === 'low') count = 30;
|
||||
if (density === 'high') count = 110;
|
||||
|
||||
this.sceneInstance = new HeroNetworkScene(container, {
|
||||
particleCount: count,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
if (this.sceneInstance) {
|
||||
this.sceneInstance.destroy();
|
||||
this.sceneInstance = null;
|
||||
}
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
export default publicWidget.registry.Theme3DHero;`
|
||||
},
|
||||
's_system_architecture.xml': {
|
||||
path: 'theme_3d_systems/views/snippets/s_system_architecture.xml',
|
||||
lang: 'xml',
|
||||
desc: 'Interactive business architecture pipeline (Customer -> Website -> Odoo ERP -> Automation)',
|
||||
code: `<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="s_system_architecture" name="System Architecture Pipeline">
|
||||
<section class="s_system_architecture py-6 position-relative">
|
||||
<div class="container">
|
||||
<div class="text-center max-w-700 mx-auto mb-5">
|
||||
<div class="oe_structure">
|
||||
<span class="badge-tech-tag mb-3">Intelligent Integration</span>
|
||||
<h2 class="display-5 fw-bold text-white mb-3">
|
||||
Unified Enterprise <span class="text-gradient-cyan">Data Flow</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="arch-pipeline-container my-5">
|
||||
<div class="arch-node-card" data-target-module="customer">
|
||||
<div class="node-icon-box"><i class="fa fa-users"></i></div>
|
||||
<h5 class="text-white mb-1">1. Customer</h5>
|
||||
</div>
|
||||
<div class="arch-connector-line"><i class="fa fa-angle-right"></i></div>
|
||||
<div class="arch-node-card" data-target-module="web">
|
||||
<div class="node-icon-box"><i class="fa fa-globe"></i></div>
|
||||
<h5 class="text-white mb-1">2. Web Systems</h5>
|
||||
</div>
|
||||
<div class="arch-connector-line"><i class="fa fa-angle-right"></i></div>
|
||||
<div class="arch-node-card border-cyan shadow-glow" data-target-module="odoo">
|
||||
<div class="node-icon-box bg-cyan text-dark"><i class="fa fa-cube"></i></div>
|
||||
<h5 class="text-gradient-cyan mb-1 fw-bold">3. Odoo 19 ERP</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
</odoo>`
|
||||
}
|
||||
};
|
||||
|
||||
const copyCurrentCode = () => {
|
||||
navigator.clipboard.writeText(fileManifest[selectedFile].code);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div id="odoo-theme-hub" className="min-h-screen bg-[#060910] text-slate-100 flex flex-col font-sans selection:bg-cyan-500/30 selection:text-cyan-200">
|
||||
{/* Top Application Bar */}
|
||||
<header className="border-b border-slate-800/80 bg-[#0a0f1d]/90 backdrop-blur-md sticky top-0 z-50 px-4 lg:px-8 py-3.5 flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-cyan-400 to-blue-600 flex items-center justify-center shadow-lg shadow-cyan-500/20">
|
||||
<Boxes className="w-5 h-5 text-slate-950 font-bold" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-extrabold tracking-wider text-white text-base">THEME 3D SYSTEMS</span>
|
||||
<span className="text-xs px-2 py-0.5 rounded-full bg-cyan-500/10 text-cyan-400 border border-cyan-500/30 font-mono font-medium">
|
||||
Odoo 19 Ready
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-slate-400">Enterprise QWeb Theme Module & Three.js Engine</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* View Switcher Tabs */}
|
||||
<nav className="flex items-center bg-slate-900/80 border border-slate-800 rounded-lg p-1">
|
||||
<button
|
||||
id="tab-btn-preview"
|
||||
onClick={() => setActiveTab('preview')}
|
||||
className={`px-3.5 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 ${
|
||||
activeTab === 'preview'
|
||||
? 'bg-gradient-to-r from-cyan-500 to-blue-600 text-slate-950 font-semibold shadow-md'
|
||||
: 'text-slate-400 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<Activity className="w-3.5 h-3.5" />
|
||||
Live Preview
|
||||
</button>
|
||||
<button
|
||||
id="tab-btn-files"
|
||||
onClick={() => setActiveTab('files')}
|
||||
className={`px-3.5 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 ${
|
||||
activeTab === 'files'
|
||||
? 'bg-gradient-to-r from-cyan-500 to-blue-600 text-slate-950 font-semibold shadow-md'
|
||||
: 'text-slate-400 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<FileCode className="w-3.5 h-3.5" />
|
||||
Module Source Files
|
||||
</button>
|
||||
<button
|
||||
id="tab-btn-architecture"
|
||||
onClick={() => setActiveTab('architecture')}
|
||||
className={`px-3.5 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 ${
|
||||
activeTab === 'architecture'
|
||||
? 'bg-gradient-to-r from-cyan-500 to-blue-600 text-slate-950 font-semibold shadow-md'
|
||||
: 'text-slate-400 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<Workflow className="w-3.5 h-3.5" />
|
||||
Odoo 19 Architecture
|
||||
</button>
|
||||
<button
|
||||
id="tab-btn-guide"
|
||||
onClick={() => setActiveTab('guide')}
|
||||
className={`px-3.5 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 ${
|
||||
activeTab === 'guide'
|
||||
? 'bg-gradient-to-r from-cyan-500 to-blue-600 text-slate-950 font-semibold shadow-md'
|
||||
: 'text-slate-400 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<Terminal className="w-3.5 h-3.5" />
|
||||
Installation Guide
|
||||
</button>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
{/* Main Content Area */}
|
||||
<main className="flex-1 flex flex-col">
|
||||
{/* VIEW 1: LIVE INTERACTIVE PREVIEW */}
|
||||
{activeTab === 'preview' && (
|
||||
<div className="flex-1 flex flex-col">
|
||||
{/* Subpage Navigator for Odoo Simulation */}
|
||||
<div className="bg-[#0b101f] border-b border-slate-800 px-6 py-2 flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-slate-400 uppercase tracking-widest font-mono">Simulated Route:</span>
|
||||
<div className="flex gap-1.5">
|
||||
{(['home', 'services', 'odoo', 'portfolio', 'about', 'contact'] as const).map((page) => (
|
||||
<button
|
||||
key={page}
|
||||
onClick={() => setActivePage(page)}
|
||||
className={`px-3 py-1 rounded text-xs font-medium capitalize transition-all ${
|
||||
activePage === page
|
||||
? 'bg-cyan-500/20 text-cyan-300 border border-cyan-500/40'
|
||||
: 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/40'
|
||||
}`}
|
||||
>
|
||||
/{page === 'home' ? '' : page}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-xs text-slate-400 font-mono">Website Builder 3D Density:</span>
|
||||
<div className="flex gap-1 bg-slate-900 border border-slate-800 p-0.5 rounded">
|
||||
{(['low', 'normal', 'high'] as const).map((d) => (
|
||||
<button
|
||||
key={d}
|
||||
onClick={() => setParticleDensity(d)}
|
||||
className={`px-2 py-0.5 text-xs uppercase font-mono rounded ${
|
||||
particleDensity === d ? 'bg-cyan-500 text-slate-950 font-bold' : 'text-slate-400'
|
||||
}`}
|
||||
>
|
||||
{d}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Simulated Live Theme Viewport */}
|
||||
<div className="flex-1 overflow-y-auto relative bg-[#060910]">
|
||||
{/* Simulated Odoo Glassmorphic Header */}
|
||||
<div className="border-b border-white/5 bg-[#060910]/80 backdrop-blur-lg px-8 py-4 flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-7 h-7 rounded bg-gradient-to-tr from-cyan-400 to-blue-600 flex items-center justify-center shadow-lg shadow-cyan-500/30">
|
||||
<div className="w-3 h-3 bg-[#060910] rounded-sm transform rotate-45" />
|
||||
</div>
|
||||
<span className="font-extrabold text-lg tracking-wider text-white">
|
||||
SYSTEMS<span className="text-cyan-400">.3D</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="hidden md:flex items-center gap-6 text-sm text-slate-300">
|
||||
<span className="hover:text-cyan-400 cursor-pointer font-medium">Services</span>
|
||||
<span className="hover:text-cyan-400 cursor-pointer font-medium">Odoo ERP</span>
|
||||
<span className="hover:text-cyan-400 cursor-pointer font-medium">Portfolio</span>
|
||||
<span className="hover:text-cyan-400 cursor-pointer font-medium">About</span>
|
||||
<span className="hover:text-cyan-400 cursor-pointer font-medium">Contact</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<a
|
||||
href="#quote"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setActivePage('contact');
|
||||
}}
|
||||
className="px-4 py-1.5 rounded-lg border border-cyan-400/40 text-cyan-300 text-xs font-semibold hover:bg-cyan-400/10 transition-all flex items-center gap-2"
|
||||
>
|
||||
<span className="w-2 h-2 rounded-full bg-emerald-400 animate-pulse shadow-sm shadow-emerald-400" />
|
||||
Get a Quote
|
||||
</a>
|
||||
<button
|
||||
onClick={() => setActivePage('odoo')}
|
||||
className="px-4 py-1.5 rounded-lg bg-gradient-to-r from-cyan-400 to-blue-500 text-slate-950 font-bold text-xs shadow-lg shadow-cyan-500/20 hover:opacity-90"
|
||||
>
|
||||
Explore ERP
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* PAGE: HOME */}
|
||||
{activePage === 'home' && (
|
||||
<div>
|
||||
{/* Hero Section with Live Three.js Canvas */}
|
||||
<section className="relative min-h-[580px] flex items-center justify-center overflow-hidden border-b border-slate-800/50">
|
||||
<canvas ref={canvasRef} className="absolute inset-0 w-full h-full pointer-events-auto" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl mx-auto px-6 text-center pointer-events-auto">
|
||||
<div className="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full bg-cyan-500/10 border border-cyan-500/30 text-cyan-400 text-xs font-mono mb-6 backdrop-blur-md">
|
||||
<Sparkles className="w-3.5 h-3.5" />
|
||||
Next-Gen Odoo 19 QWeb Architecture & Web Systems
|
||||
</div>
|
||||
|
||||
<h1 className="text-4xl md:text-6xl font-extrabold text-white tracking-tight leading-tight mb-6">
|
||||
Architecting{' '}
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-cyan-400 via-blue-400 to-purple-500">
|
||||
Intelligent Systems
|
||||
</span>{' '}
|
||||
For High-Growth Enterprises
|
||||
</h1>
|
||||
|
||||
<p className="text-base md:text-lg text-slate-400 max-w-2xl mx-auto mb-8 leading-relaxed">
|
||||
We build custom web systems, high-concurrency APIs, and seamlessly unified Odoo ERP solutions with
|
||||
automated business intelligence workflows.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-wrap items-center justify-center gap-4">
|
||||
<button
|
||||
onClick={() => setActivePage('services')}
|
||||
className="px-6 py-3 rounded-xl bg-gradient-to-r from-cyan-400 to-blue-500 text-slate-950 font-bold text-sm shadow-xl shadow-cyan-500/25 hover:scale-[1.02] transition-all flex items-center gap-2"
|
||||
>
|
||||
Explore Our Solutions
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActivePage('contact')}
|
||||
className="px-6 py-3 rounded-xl border border-cyan-500/40 text-cyan-300 font-semibold text-sm hover:bg-cyan-500/10 transition-all"
|
||||
>
|
||||
Start Your Project
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* System Architecture Flow */}
|
||||
<section className="py-16 px-6 max-w-6xl mx-auto">
|
||||
<div className="text-center mb-12">
|
||||
<span className="text-xs uppercase font-mono tracking-widest text-cyan-400">Intelligent Integration</span>
|
||||
<h2 className="text-2xl md:text-4xl font-bold text-white mt-2">Unified Enterprise Data Flow</h2>
|
||||
<p className="text-slate-400 text-sm mt-2 max-w-xl mx-auto">
|
||||
Customer touchpoints flowing smoothly into custom web portals and core Odoo 19 automated pipelines.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 items-center">
|
||||
<div className="p-6 rounded-2xl bg-slate-900/60 border border-slate-800 hover:border-cyan-500/40 transition-all text-center group">
|
||||
<div className="w-12 h-12 rounded-xl bg-cyan-500/10 border border-cyan-500/20 text-cyan-400 flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform">
|
||||
<Globe className="w-6 h-6" />
|
||||
</div>
|
||||
<h4 className="text-white font-bold text-base mb-1">1. Customer</h4>
|
||||
<p className="text-xs text-slate-400">Omnichannel & Portal</p>
|
||||
</div>
|
||||
|
||||
<div className="p-6 rounded-2xl bg-slate-900/60 border border-slate-800 hover:border-cyan-500/40 transition-all text-center group">
|
||||
<div className="w-12 h-12 rounded-xl bg-blue-500/10 border border-blue-500/20 text-blue-400 flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform">
|
||||
<Code2 className="w-6 h-6" />
|
||||
</div>
|
||||
<h4 className="text-white font-bold text-base mb-1">2. Web Systems</h4>
|
||||
<p className="text-xs text-slate-400">Custom React/REST APIs</p>
|
||||
</div>
|
||||
|
||||
<div className="p-6 rounded-2xl bg-slate-900/90 border-2 border-cyan-500/60 shadow-xl shadow-cyan-500/10 text-center group relative">
|
||||
<div className="absolute -top-3 right-4 px-2 py-0.5 bg-cyan-500 text-slate-950 text-[10px] font-bold rounded-full uppercase">
|
||||
Core Hub
|
||||
</div>
|
||||
<div className="w-12 h-12 rounded-xl bg-cyan-500 text-slate-950 flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform">
|
||||
<Boxes className="w-6 h-6 font-bold" />
|
||||
</div>
|
||||
<h4 className="text-cyan-300 font-bold text-base mb-1">3. Odoo 19 ERP</h4>
|
||||
<p className="text-xs text-slate-400">Central Nervous System</p>
|
||||
</div>
|
||||
|
||||
<div className="p-6 rounded-2xl bg-slate-900/60 border border-slate-800 hover:border-cyan-500/40 transition-all text-center group">
|
||||
<div className="w-12 h-12 rounded-xl bg-purple-500/10 border border-purple-500/20 text-purple-400 flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform">
|
||||
<Workflow className="w-6 h-6" />
|
||||
</div>
|
||||
<h4 className="text-white font-bold text-base mb-1">4. Automation</h4>
|
||||
<p className="text-xs text-slate-400">CRM, Sales & Accounting</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Core Services Cards */}
|
||||
<section className="py-12 px-6 max-w-6xl mx-auto">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<div>
|
||||
<span className="text-xs uppercase font-mono tracking-widest text-cyan-400">Services</span>
|
||||
<h2 className="text-2xl font-bold text-white mt-1">High-Impact Engineering</h2>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setActivePage('services')}
|
||||
className="text-xs text-cyan-400 hover:underline flex items-center gap-1 font-semibold"
|
||||
>
|
||||
View all 8 services <ChevronRight className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="p-6 rounded-2xl bg-slate-900/40 border border-slate-800/80 hover:border-cyan-500/40 transition-all">
|
||||
<Cpu className="w-8 h-8 text-cyan-400 mb-4" />
|
||||
<h3 className="text-lg font-bold text-white mb-2">Custom Web Systems</h3>
|
||||
<p className="text-xs text-slate-400 leading-relaxed mb-4">
|
||||
Bespoke enterprise portals, microservices, and reactive web applications tailored to unique operational demands.
|
||||
</p>
|
||||
<span className="text-xs font-semibold text-cyan-400 flex items-center gap-1">
|
||||
Learn More <ArrowRight className="w-3 h-3" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="p-6 rounded-2xl bg-slate-900/40 border border-slate-800/80 hover:border-purple-500/40 transition-all">
|
||||
<Database className="w-8 h-8 text-purple-400 mb-4" />
|
||||
<h3 className="text-lg font-bold text-white mb-2">Odoo ERP Solutions</h3>
|
||||
<p className="text-xs text-slate-400 leading-relaxed mb-4">
|
||||
End-to-end Odoo 19 implementation, custom Python module development, and database architecture.
|
||||
</p>
|
||||
<span className="text-xs font-semibold text-cyan-400 flex items-center gap-1">
|
||||
Learn More <ArrowRight className="w-3 h-3" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="p-6 rounded-2xl bg-slate-900/40 border border-slate-800/80 hover:border-cyan-500/40 transition-all">
|
||||
<Workflow className="w-8 h-8 text-cyan-400 mb-4" />
|
||||
<h3 className="text-lg font-bold text-white mb-2">Business Automation</h3>
|
||||
<p className="text-xs text-slate-400 leading-relaxed mb-4">
|
||||
Automated webhooks, async task workers, and real-time triggers synchronizing CRM with finance.
|
||||
</p>
|
||||
<span className="text-xs font-semibold text-cyan-400 flex items-center gap-1">
|
||||
Learn More <ArrowRight className="w-3 h-3" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* SUBPAGE: SERVICES */}
|
||||
{activePage === 'services' && (
|
||||
<div className="max-w-6xl mx-auto px-6 py-12">
|
||||
<div className="text-center mb-12">
|
||||
<span className="text-xs font-mono uppercase text-cyan-400 tracking-widest">Directory</span>
|
||||
<h1 className="text-3xl font-extrabold text-white mt-2">Comprehensive Systems & ERP Services</h1>
|
||||
<p className="text-slate-400 text-sm mt-2">Everything from custom Python modules to high-load cloud hosting.</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{[
|
||||
{ title: 'Custom Web Systems', icon: Globe, desc: 'Enterprise client portals and multi-tenant architectures.' },
|
||||
{ title: 'Odoo ERP Solutions', icon: Boxes, desc: 'Full lifecycle Odoo 19 setup and custom views.' },
|
||||
{ title: 'Business Automation', icon: Workflow, desc: 'Zapier/Webhook/Cron pipeline automation.' },
|
||||
{ title: 'eCommerce Solutions', icon: Cpu, desc: 'High conversion multi-currency digital shops.' },
|
||||
{ title: 'CRM Solutions', icon: ShieldCheck, desc: 'Lead tracking and omnichannel pipeline routing.' },
|
||||
{ title: 'API & 3rd-Party Sync', icon: Code2, desc: 'REST, GraphQL, Stripe, PayPal, and carrier sync.' },
|
||||
{ title: 'Custom Dashboards', icon: Activity, desc: 'Executive KPI reporting and real-time telemetry.' },
|
||||
{ title: 'Cloud & SLA Support', icon: Terminal, desc: 'Kubernetes deployment and 99.98% uptime SLA.' },
|
||||
].map((srv, idx) => (
|
||||
<div key={idx} className="p-5 rounded-xl bg-slate-900/60 border border-slate-800 hover:border-cyan-500/50 transition-all">
|
||||
<srv.icon className="w-6 h-6 text-cyan-400 mb-3" />
|
||||
<h4 className="font-bold text-white text-sm mb-1">{srv.title}</h4>
|
||||
<p className="text-xs text-slate-400">{srv.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* SUBPAGE: ODOO SOLUTIONS */}
|
||||
{activePage === 'odoo' && (
|
||||
<div className="max-w-6xl mx-auto px-6 py-12">
|
||||
<div className="text-center mb-12">
|
||||
<span className="text-xs font-mono uppercase text-purple-400 tracking-widest">Odoo 19 Engine</span>
|
||||
<h1 className="text-3xl font-extrabold text-white mt-2">Connected Odoo ERP Ecosystem</h1>
|
||||
<p className="text-slate-400 text-sm mt-2">Native module integration, QWeb templating, and Owl UI widgets.</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{[
|
||||
{ mod: 'Odoo CRM & Sales', desc: 'Seamless lead scoring and quotation creation.' },
|
||||
{ mod: 'Odoo Accounting', desc: 'Automated bank feed reconciliation & e-invoices.' },
|
||||
{ mod: 'Odoo Inventory & MRP', desc: 'Multi-warehouse double-entry stock operations.' },
|
||||
{ mod: 'Odoo Website & Portal', desc: 'High-speed QWeb frontend with 3D enhancement.' },
|
||||
{ mod: 'Odoo Studio & Custom Models', desc: 'Tailored Python business logic & database schemas.' },
|
||||
{ mod: 'Odoo Migration (16-18 to 19)', desc: 'Zero data-loss migrations with custom script validation.' },
|
||||
].map((item, idx) => (
|
||||
<div key={idx} className="p-6 rounded-2xl bg-slate-900/80 border border-purple-500/20 hover:border-purple-500/60 transition-all">
|
||||
<div className="w-10 h-10 rounded-lg bg-purple-500/10 text-purple-400 flex items-center justify-center font-bold mb-4">
|
||||
0{idx + 1}
|
||||
</div>
|
||||
<h3 className="font-bold text-white text-base mb-2">{item.mod}</h3>
|
||||
<p className="text-xs text-slate-400">{item.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* SUBPAGE: CONTACT */}
|
||||
{activePage === 'contact' && (
|
||||
<div className="max-w-4xl mx-auto px-6 py-12">
|
||||
<div className="text-center mb-8">
|
||||
<span className="text-xs font-mono uppercase text-cyan-400 tracking-widest">Initiate Project</span>
|
||||
<h1 className="text-3xl font-extrabold text-white mt-2">Transmit Project Parameters</h1>
|
||||
<p className="text-slate-400 text-sm mt-2">Connects natively to Odoo CRM (<code className="text-cyan-400 font-mono">crm.lead</code> model).</p>
|
||||
</div>
|
||||
|
||||
<div className="p-8 rounded-2xl bg-slate-900/90 border border-slate-800">
|
||||
<form onSubmit={(e) => { e.preventDefault(); alert('Lead simulated! In Odoo 19, this posts to /website/form/ and generates a crm.lead record.'); }} className="space-y-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-slate-300 mb-1">Your Name *</label>
|
||||
<input type="text" required placeholder="Alex Vance" className="w-full px-3.5 py-2.5 rounded-lg bg-slate-950 border border-slate-800 text-white text-sm focus:border-cyan-400 focus:outline-none" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-slate-300 mb-1">Work Email *</label>
|
||||
<input type="email" required placeholder="alex@enterprise.com" className="w-full px-3.5 py-2.5 rounded-lg bg-slate-950 border border-slate-800 text-white text-sm focus:border-cyan-400 focus:outline-none" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-slate-300 mb-1">Company</label>
|
||||
<input type="text" placeholder="Acme Logistics" className="w-full px-3.5 py-2.5 rounded-lg bg-slate-950 border border-slate-800 text-white text-sm focus:border-cyan-400 focus:outline-none" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-slate-300 mb-1">Primary Interest</label>
|
||||
<select className="w-full px-3.5 py-2.5 rounded-lg bg-slate-950 border border-slate-800 text-white text-sm focus:border-cyan-400 focus:outline-none">
|
||||
<option>Odoo 19 ERP Implementation</option>
|
||||
<option>Custom Web Systems & Portals</option>
|
||||
<option>Business Automation</option>
|
||||
<option>High-Scale API Integration</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-slate-300 mb-1">Project Scope *</label>
|
||||
<textarea rows={4} required placeholder="Describe your architecture requirements, data volume, and timeline..." className="w-full px-3.5 py-2.5 rounded-lg bg-slate-950 border border-slate-800 text-white text-sm focus:border-cyan-400 focus:outline-none" />
|
||||
</div>
|
||||
|
||||
<button type="submit" className="w-full py-3 rounded-xl bg-gradient-to-r from-cyan-400 to-blue-500 text-slate-950 font-bold text-sm shadow-lg shadow-cyan-500/20 hover:opacity-95">
|
||||
Submit Inquiry to Odoo CRM Lead Pipeline
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* VIEW 2: MODULE SOURCE FILES EXPLORER */}
|
||||
{activeTab === 'files' && (
|
||||
<div className="flex-1 flex overflow-hidden">
|
||||
{/* File Sidebar */}
|
||||
<div className="w-72 border-r border-slate-800 bg-[#090d18] p-4 overflow-y-auto">
|
||||
<div className="text-xs font-mono uppercase tracking-wider text-slate-400 mb-3 flex items-center gap-1.5">
|
||||
<FolderGit2 className="w-4 h-4 text-cyan-400" />
|
||||
theme_3d_systems/
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
{Object.keys(fileManifest).map((fileKey) => (
|
||||
<button
|
||||
key={fileKey}
|
||||
onClick={() => setSelectedFile(fileKey)}
|
||||
className={`w-full text-left px-3 py-2 rounded-lg text-xs font-mono flex items-center justify-between transition-all ${
|
||||
selectedFile === fileKey
|
||||
? 'bg-cyan-500/15 text-cyan-300 border border-cyan-500/40 font-semibold'
|
||||
: 'text-slate-400 hover:bg-slate-800/60 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<span>{fileKey}</span>
|
||||
<ChevronRight className="w-3.5 h-3.5 opacity-60" />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Code Viewer */}
|
||||
<div className="flex-1 flex flex-col bg-[#05070d] overflow-hidden">
|
||||
<div className="border-b border-slate-800/80 px-6 py-3 flex items-center justify-between bg-[#080c16]">
|
||||
<div>
|
||||
<span className="font-mono text-xs text-cyan-400">{fileManifest[selectedFile].path}</span>
|
||||
<p className="text-xs text-slate-400 mt-0.5">{fileManifest[selectedFile].desc}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={copyCurrentCode}
|
||||
className="px-3 py-1.5 rounded bg-slate-800 text-xs font-mono text-slate-200 hover:bg-slate-700 flex items-center gap-1.5 transition-all"
|
||||
>
|
||||
{copied ? <CheckCircle className="w-3.5 h-3.5 text-emerald-400" /> : <Copy className="w-3.5 h-3.5" />}
|
||||
{copied ? 'Copied to Clipboard' : 'Copy Code'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-auto p-6">
|
||||
<pre className="font-mono text-xs leading-relaxed text-slate-300">
|
||||
<code>{fileManifest[selectedFile].code}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* VIEW 3: ODOO 19 ARCHITECTURE */}
|
||||
{activeTab === 'architecture' && (
|
||||
<div className="flex-1 max-w-5xl mx-auto p-8 overflow-y-auto space-y-6">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white">Odoo 19 Native Integration Architecture</h2>
|
||||
<p className="text-sm text-slate-400 mt-1">
|
||||
How Theme 3D Systems adheres strictly to Odoo's QWeb inheritance, PublicWidget lifecycles, and Website Builder standards.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="p-6 rounded-2xl bg-slate-900/60 border border-slate-800 space-y-3">
|
||||
<div className="flex items-center gap-2 text-cyan-400 font-bold text-sm">
|
||||
<CheckCircle className="w-4 h-4" />
|
||||
1. Zero Content Destruction
|
||||
</div>
|
||||
<p className="text-xs text-slate-400 leading-relaxed">
|
||||
All headings, badges, text, and buttons live directly in QWeb XML using standard <code className="text-cyan-300 font-mono">oe_structure</code>. Website administrators can click and edit any word directly in the Odoo Website Editor without touching JavaScript.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="p-6 rounded-2xl bg-slate-900/60 border border-slate-800 space-y-3">
|
||||
<div className="flex items-center gap-2 text-purple-400 font-bold text-sm">
|
||||
<CheckCircle className="w-4 h-4" />
|
||||
2. Three.js Lifecycle & Memory Safety
|
||||
</div>
|
||||
<p className="text-xs text-slate-400 leading-relaxed">
|
||||
Three.js WebGL scenes are dynamically lazy-loaded. When entering Website Builder edit mode or leaving the view, <code className="text-purple-300 font-mono">destroy()</code> cancels animation frames and releases GPU textures to prevent browser leaks.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="p-6 rounded-2xl bg-slate-900/60 border border-slate-800 space-y-3">
|
||||
<div className="flex items-center gap-2 text-cyan-400 font-bold text-sm">
|
||||
<CheckCircle className="w-4 h-4" />
|
||||
3. Odoo 19 ES6 Asset Bundles
|
||||
</div>
|
||||
<p className="text-xs text-slate-400 leading-relaxed">
|
||||
Assets are separated cleanly into <code className="text-cyan-300 font-mono">web.assets_frontend</code> for critical SCSS and lightweight widgets, and <code className="text-cyan-300 font-mono">website.assets_editor</code> for sidebar options.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="p-6 rounded-2xl bg-slate-900/60 border border-slate-800 space-y-3">
|
||||
<div className="flex items-center gap-2 text-emerald-400 font-bold text-sm">
|
||||
<CheckCircle className="w-4 h-4" />
|
||||
4. Native Lead Form Routing
|
||||
</div>
|
||||
<p className="text-xs text-slate-400 leading-relaxed">
|
||||
The contact page uses Odoo's native <code className="text-emerald-300 font-mono">s_website_form</code> posting to <code className="text-emerald-300 font-mono">crm.lead</code> with standard CSRF protection, requiring no separate backend server.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* VIEW 4: INSTALLATION GUIDE */}
|
||||
{activeTab === 'guide' && (
|
||||
<div className="flex-1 max-w-4xl mx-auto p-8 overflow-y-auto space-y-6">
|
||||
<h2 className="text-2xl font-bold text-white">How to Install in Odoo 19 (Community & Enterprise)</h2>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="p-5 rounded-xl bg-slate-900 border border-slate-800">
|
||||
<div className="font-bold text-sm text-cyan-400 mb-2">Step 1: Copy to your custom addons directory</div>
|
||||
<pre className="p-3 rounded bg-slate-950 font-mono text-xs text-slate-300 overflow-x-auto">
|
||||
<code>cp -r theme_3d_systems /path/to/odoo/custom-addons/</code>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<div className="p-5 rounded-xl bg-slate-900 border border-slate-800">
|
||||
<div className="font-bold text-sm text-cyan-400 mb-2">Step 2: Update Addons List in Odoo 19</div>
|
||||
<p className="text-xs text-slate-400 mb-2">
|
||||
Activate Developer Mode in Odoo Settings, navigate to <strong>Apps</strong> > <strong>Update Apps List</strong>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="p-5 rounded-xl bg-slate-900 border border-slate-800">
|
||||
<div className="font-bold text-sm text-cyan-400 mb-2">Step 3: Install Theme 3D Systems</div>
|
||||
<p className="text-xs text-slate-400">
|
||||
Search for "Theme 3D Systems" under the Themes filter in the Apps menu, click <strong>Install / Activate Theme</strong>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue