Resume-Website/blog/artdeco-article-template.html

759 lines
23 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Project Article - Tech Blog</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--deep-navy: #0A1128;
--rich-gold: #D4AF37;
--warm-gold: #F4E5C2;
--cream: #FFF8E7;
--charcoal: #2C2C2C;
--silver: #C0C0C0;
--burgundy: #7C2D37;
}
body {
font-family: 'Didot', 'Bodoni MT', 'Playfair Display', Georgia, serif;
line-height: 1.8;
color: var(--charcoal);
background: linear-gradient(180deg, var(--deep-navy) 0%, #1a2847 100%);
position: relative;
overflow-x: hidden;
}
/* Art Deco geometric background pattern */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
repeating-linear-gradient(45deg, transparent, transparent 35px, rgba(212, 175, 55, 0.03) 35px, rgba(212, 175, 55, 0.03) 70px),
repeating-linear-gradient(-45deg, transparent, transparent 35px, rgba(212, 175, 55, 0.03) 35px, rgba(212, 175, 55, 0.03) 70px);
z-index: -1;
}
/* Navigation */
nav {
background: rgba(10, 17, 40, 0.95);
border-bottom: 2px solid var(--rich-gold);
padding: 1.0rem 0;
position: sticky;
top: 0;
z-index: 100;
backdrop-filter: blur(10px);
}
.nav-content {
max-width: 1000px;
margin: 0 auto;
padding: 0 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.nav-logo {
font-size: 1.5rem;
font-weight: 300;
color: var(--warm-gold);
text-decoration: none;
letter-spacing: 0.2em;
text-transform: uppercase;
}
.nav-back {
color: var(--silver);
text-decoration: none;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 0.9rem;
letter-spacing: 0.1em;
text-transform: uppercase;
transition: color 0.3s;
}
.nav-back:hover {
color: var(--rich-gold);
}
.nav-back::before {
content: '←';
margin-right: 0.5rem;
}
/* Article Container */
.article-container {
max-width: 1000px;
margin: 4rem auto;
padding: 0 2rem;
}
/* Article Header */
.article-header {
background: var(--cream);
padding: 4rem 4rem 3rem;
border: 2px solid var(--rich-gold);
position: relative;
margin-bottom: 3rem;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
}
/* Corner decorations */
.article-header::before,
.article-header::after {
content: '';
position: absolute;
width: 60px;
height: 60px;
border: 2px solid var(--rich-gold);
}
.article-header::before {
top: 0;
left: 0;
border-right: none;
border-bottom: none;
}
.article-header::after {
bottom: 0;
right: 0;
border-left: none;
border-top: none;
}
.article-number {
font-size: 4rem;
font-weight: 300;
color: var(--rich-gold);
line-height: 1;
margin-bottom: 1rem;
}
.article-meta {
display: flex;
gap: 2rem;
margin-bottom: 2rem;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.15em;
}
.article-category {
color: var(--burgundy);
font-weight: 700;
position: relative;
padding-left: 1rem;
}
.article-category::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%) rotate(45deg);
width: 6px;
height: 6px;
background: var(--rich-gold);
}
.article-title {
font-size: 3.5rem;
font-weight: 400;
color: var(--deep-navy);
line-height: 1.2;
letter-spacing: 0.02em;
margin-bottom: 1.5rem;
}
.article-subtitle {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 1.25rem;
line-height: 1.6;
color: var(--charcoal);
font-weight: 400;
}
/* Tech Stack */
.tech-stack {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-top: 2rem;
padding-top: 2rem;
border-top: 2px solid var(--rich-gold);
}
.tech-item {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 0.9rem;
font-weight: 600;
color: var(--deep-navy);
padding: 0.75rem 1.5rem;
background: linear-gradient(135deg, rgba(212, 175, 55, 0.15), rgba(212, 175, 55, 0.05));
border-left: 3px solid var(--rich-gold);
letter-spacing: 0.05em;
}
/* Featured Image */
.featured-image {
width: 100%;
height: 500px;
background: linear-gradient(135deg, var(--deep-navy) 0%, var(--burgundy) 100%);
border: 2px solid var(--rich-gold);
margin-bottom: 3rem;
position: relative;
overflow: hidden;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
}
/* Sunburst pattern on image */
.featured-image::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 200%;
height: 200%;
background: repeating-conic-gradient(
from 0deg,
rgba(212, 175, 55, 0.1) 0deg 10deg,
transparent 10deg 20deg
);
transform: translate(-50%, -50%);
}
.image-placeholder {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 6rem;
filter: drop-shadow(2px 2px 4px rgba(0, 0, 0, 0.5));
}
/* Article Content */
.article-content {
background: var(--cream);
padding: 4rem;
border: 2px solid var(--rich-gold);
position: relative;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
}
/* Corner decorations for content */
.article-content::before,
.article-content::after {
content: '';
position: absolute;
width: 40px;
height: 40px;
border: 2px solid var(--rich-gold);
}
.article-content::before {
top: 0;
right: 0;
border-left: none;
border-bottom: none;
}
.article-content::after {
bottom: 0;
left: 0;
border-right: none;
border-top: none;
}
.article-content h2 {
font-size: 2rem;
font-weight: 400;
color: var(--deep-navy);
margin: 3rem 0 1.5rem 0;
letter-spacing: 0.02em;
position: relative;
padding-bottom: 1rem;
}
.article-content h2::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 80px;
height: 2px;
background: var(--rich-gold);
}
.article-content h2:first-child {
margin-top: 0;
}
.article-content h3 {
font-size: 1.5rem;
font-weight: 400;
color: var(--burgundy);
margin: 2.5rem 0 1rem 0;
letter-spacing: 0.02em;
}
.article-content p {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 1.1rem;
line-height: 1.9;
margin-bottom: 1.5rem;
color: var(--charcoal);
}
.article-content ul,
.article-content ol {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 1.1rem;
line-height: 1.9;
margin: 1.5rem 0 1.5rem 2rem;
color: var(--charcoal);
}
.article-content li {
margin-bottom: 0.75rem;
padding-left: 0.5rem;
}
.article-content ul li::marker {
color: var(--rich-gold);
}
.article-content code {
font-family: 'Courier New', monospace;
background: rgba(212, 175, 55, 0.1);
padding: 0.2rem 0.5rem;
border-radius: 3px;
font-size: 0.95rem;
color: var(--burgundy);
}
.article-content pre {
background: var(--charcoal);
color: var(--warm-gold);
padding: 1.5rem;
border-radius: 4px;
overflow-x: auto;
margin: 2rem 0;
border-left: 4px solid var(--rich-gold);
}
.article-content pre code {
background: none;
color: var(--warm-gold);
padding: 0;
}
.article-content blockquote {
border-left: 4px solid var(--rich-gold);
padding-left: 2rem;
margin: 2rem 0;
font-style: italic;
color: var(--burgundy);
background: linear-gradient(90deg, rgba(212, 175, 55, 0.05), transparent);
padding: 1.5rem 2rem;
}
/* Inline images */
.article-content img {
max-width: 100%;
height: auto;
margin: 2rem 0;
border: 2px solid var(--rich-gold);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}
/* Decorative divider */
.deco-divider {
display: flex;
align-items: center;
justify-content: center;
margin: 3rem 0;
gap: 1rem;
}
.deco-divider::before,
.deco-divider::after {
content: '';
width: 100px;
height: 2px;
background: linear-gradient(90deg, transparent, var(--rich-gold), transparent);
}
.deco-divider .diamond {
width: 12px;
height: 12px;
background: var(--rich-gold);
transform: rotate(45deg);
}
/* Footer */
footer {
text-align: center;
padding: 4rem 0;
color: var(--silver);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 0.9rem;
letter-spacing: 0.15em;
text-transform: uppercase;
margin-top: 4rem;
}
.footer-ornament {
width: 200px;
height: 2px;
background: linear-gradient(90deg, transparent, var(--rich-gold), transparent);
margin: 0 auto 1.5rem;
position: relative;
}
.footer-ornament::before {
content: '';
position: absolute;
width: 10px;
height: 10px;
background: var(--rich-gold);
transform: rotate(45deg);
top: -4px;
left: 50%;
margin-left: -5px;
}
/* Responsive */
@media (max-width: 768px) {
.article-header,
.article-content {
padding: 2rem;
}
.article-title {
font-size: 2.5rem;
}
.article-number {
font-size: 3rem;
}
.featured-image {
height: 300px;
}
.image-placeholder {
font-size: 4rem;
}
.article-container {
padding: 0 1rem;
margin: 2rem auto;
}
.nav-content {
padding: 0 1rem;
}
.nav-logo {
font-size: 1.2rem;
}
}
</style>
</head>
<body>
<!-- Navigation -->
<nav>
<div class="nav-content">
<a href="#" class="nav-logo">Atelier</a>
<a href="#" class="nav-back">Back to Projects</a>
</div>
</nav>
<!-- Article Container -->
<div class="article-container">
<!-- Article Header -->
<header class="article-header">
<div class="article-number">01</div>
<div class="article-meta">
<span class="article-category">Web Development</span>
<span>November 2025</span>
</div>
<h1 class="article-title">Building a Real-Time Collaborative Editor</h1>
<p class="article-subtitle">
A deep dive into creating a production-ready collaborative text editor using WebSockets,
operational transformation, and modern web technologies.
</p>
<div class="tech-stack">
<div class="tech-item">React</div>
<div class="tech-item">Node.js</div>
<div class="tech-item">WebSocket</div>
<div class="tech-item">MongoDB</div>
<div class="tech-item">Redis</div>
</div>
</header>
<!-- Featured Image -->
<div class="featured-image">
<div class="image-placeholder"></div>
</div>
<!-- Article Content -->
<article class="article-content">
<h2>The Challenge</h2>
<p>
Building a real-time collaborative editor presents unique technical challenges. When multiple users edit
the same document simultaneously, conflicts arise that must be resolved elegantly without losing data or
disrupting the user experience. This project explores operational transformation algorithms and their
implementation in a modern web application.
</p>
<p>
The goal was to create an editor that feels as responsive as Google Docs while maintaining data consistency
across all connected clients. Every keystroke needed to be transmitted, transformed, and applied in real-time
without introducing latency or conflicts.
</p>
<div class="deco-divider">
<div class="diamond"></div>
</div>
<h2>Technical Architecture</h2>
<p>
The system is built on a microservices architecture with distinct components handling different aspects
of the collaborative experience:
</p>
<h3>WebSocket Server</h3>
<p>
At the heart of the system is a Node.js WebSocket server that manages all real-time connections. Each
document session creates a room where clients can join, and all operations are broadcast through this central hub.
</p>
<ul>
<li>Handles client connections and disconnections gracefully</li>
<li>Broadcasts operations to all connected clients in a room</li>
<li>Implements heartbeat mechanisms to detect stale connections</li>
<li>Scales horizontally using Redis pub/sub for multi-server deployments</li>
</ul>
<h3>Operational Transformation</h3>
<p>
The core algorithm that makes collaboration possible is operational transformation (OT). When two users
edit different parts of the document, their operations must be transformed relative to each other to
maintain consistency.
</p>
<blockquote>
"Operational transformation is the mathematical foundation that allows distributed systems to converge
to the same state despite concurrent modifications."
</blockquote>
<p>
Our implementation uses a three-operation model: insert, delete, and retain. Each operation carries
positional information that gets transformed when concurrent operations occur.
</p>
<div class="deco-divider">
<div class="diamond"></div>
</div>
<h2>Key Features</h2>
<p>
The final implementation includes several sophisticated features that enhance the collaborative experience:
</p>
<ol>
<li><strong>Cursor Tracking:</strong> Real-time display of where other users are typing</li>
<li><strong>Presence Indicators:</strong> Shows who's currently viewing the document</li>
<li><strong>Conflict-Free Resolution:</strong> Automatic handling of concurrent edits</li>
<li><strong>Undo/Redo:</strong> Full history management that works across collaborative sessions</li>
<li><strong>Rich Text Formatting:</strong> Support for bold, italic, lists, and more</li>
</ol>
<h3>Performance Optimizations</h3>
<p>
To ensure smooth performance even with large documents and many concurrent users, several optimizations
were implemented:
</p>
<ul>
<li>Operation batching to reduce network overhead</li>
<li>Delta compression for efficient data transmission</li>
<li>Lazy loading of document history</li>
<li>Client-side caching with service workers</li>
</ul>
<div class="deco-divider">
<div class="diamond"></div>
</div>
<h2>Code Implementation</h2>
<p>
The operational transformation logic is implemented in JavaScript. Here's a simplified example of how
operations are transformed when they conflict:
</p>
<pre><code>function transformOperation(op1, op2) {
// If operations affect different positions, no transformation needed
if (op1.position < op2.position) {
return op1;
}
// Transform op1 based on op2's changes
if (op2.type === 'insert') {
return {
...op1,
position: op1.position + op2.length
};
}
if (op2.type === 'delete') {
return {
...op1,
position: Math.max(op1.position - op2.length, op2.position)
};
}
return op1;
}</code></pre>
<h3>WebSocket Event Handler</h3>
<p>
The server-side WebSocket handler manages incoming operations and broadcasts them to all connected clients:
</p>
<pre><code>io.on('connection', (socket) => {
console.log('Client connected:', socket.id);
socket.on('join-document', (docId) => {
socket.join(docId);
socket.to(docId).emit('user-joined', {
userId: socket.id,
timestamp: Date.now()
});
});
socket.on('operation', (data) => {
const { docId, operation, version } = data;
// Transform and broadcast operation
const transformed = applyTransformation(operation, version);
socket.to(docId).emit('operation', transformed);
// Save to database
saveOperation(docId, transformed);
});
});</code></pre>
<h3>React Component Example</h3>
<p>
On the client side, React components manage the editor state and handle user input:
</p>
<pre><code>const CollaborativeEditor = () => {
const [content, setContent] = useState('');
const [cursors, setCursors] = useState({});
const wsRef = useRef(null);
useEffect(() => {
// Connect to WebSocket server
wsRef.current = io('wss://api.example.com');
wsRef.current.on('operation', (op) => {
setContent(prev => applyOperation(prev, op));
});
wsRef.current.on('cursor-move', (data) => {
setCursors(prev => ({
...prev,
[data.userId]: data.position
}));
});
return () => wsRef.current.disconnect();
}, []);
return (
&lt;div className="editor"&gt;
&lt;textarea
value={content}
onChange={handleChange}
onSelect={handleCursorMove}
/&gt;
{renderCursors(cursors)}
&lt;/div&gt;
);
};</code></pre>
<div class="deco-divider">
<div class="diamond"></div>
</div>
<h2>Lessons Learned</h2>
<p>
Throughout this project, several important insights emerged about building real-time collaborative systems:
</p>
<p>
<strong>Network Reliability:</strong> Never assume the network is stable. Implementing robust reconnection
logic and conflict resolution for offline edits proved essential for a production-ready system.
</p>
<p>
<strong>State Management:</strong> Keeping client and server state synchronized requires careful attention
to edge cases. The operational transformation algorithm must handle not just simple concurrent edits, but
also complex scenarios involving multiple clients making rapid changes.
</p>
<p>
<strong>User Experience:</strong> The technical implementation, no matter how elegant, means nothing if
users experience lag or data loss. Optimizing for perceived performance was as important as actual performance.
</p>
<div class="deco-divider">
<div class="diamond"></div>
</div>
<h2>Future Enhancements</h2>
<p>
While the current implementation is robust, several exciting enhancements are planned for future iterations:
</p>
<ul>
<li>End-to-end encryption for sensitive documents</li>
<li>Voice and video integration for enhanced collaboration</li>
<li>AI-powered suggestions and auto-completion</li>
<li>Mobile app support with native performance</li>
<li>Advanced permission systems for enterprise deployments</li>
</ul>
<p>
This project demonstrates that building truly collaborative software requires deep understanding of
distributed systems, careful attention to user experience, and thoughtful architecture decisions. The
result is a system that feels magical to users while being built on solid engineering principles.
</p>
</article>
</div>
<!-- Footer -->
<footer>
<div class="footer-ornament"></div>
<p>Crafted with Precision & Elegance © 2025</p>
</footer>
</body>
</html>