Files
g11-m3/3_Creating a Social Media Feed with Vue.js and APIs.html
2026-01-20 17:54:05 +03:00

1185 lines
36 KiB
HTML

<!DOCTYPE html>
<!-- saved from url=(0069)file:///Users/home/Downloads/deepseek_html_20260120_cab869%20(2).html -->
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Creating a Social Media Feed with Vue.js and APIs</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
}
body {
background: #f8fafc;
height: 100vh;
display: flex;
flex-direction: column;
padding: 20px;
}
.container {
flex: 1;
display: flex;
flex-direction: column;
max-width: 1000px;
margin: 0 auto;
width: 100%;
height: calc(100vh - 80px);
}
.slide {
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.08);
padding: 30px 40px;
margin: 10px 0;
display: none;
flex: 1;
overflow-y: auto;
}
.slide.active {
display: flex;
flex-direction: column;
}
h1 {
color: #42b883;
font-size: 2.2rem;
margin-bottom: 20px;
text-align: center;
}
h2 {
color: #2c3e50;
font-size: 1.8rem;
margin-bottom: 15px;
}
h3 {
color: #35495e;
font-size: 1.4rem;
margin: 20px 0 10px 0;
}
p {
font-size: 1.1rem;
line-height: 1.6;
margin: 15px 0;
color: #4a5568;
}
.code-block {
background: #1a202c;
color: #e2e8f0;
padding: 20px;
border-radius: 6px;
margin: 15px 0;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 0.95rem;
line-height: 1.5;
white-space: pre-wrap;
overflow-wrap: break-word;
}
.instruction-block {
background: #f0f8ff;
border-left: 4px solid #42b883;
padding: 15px;
margin: 15px 0;
border-radius: 0 4px 4px 0;
}
.analogy-block {
background: #f0fff4;
border-left: 4px solid #38b2ac;
padding: 15px;
margin: 15px 0;
border-radius: 0 4px 4px 0;
}
.step-number {
display: inline-block;
background: #42b883;
color: white;
width: 24px;
height: 24px;
border-radius: 50%;
text-align: center;
line-height: 24px;
margin-right: 10px;
font-weight: bold;
}
.nav-container {
display: flex;
justify-content: space-between;
margin-top: 25px;
padding-top: 20px;
border-top: 1px solid #e2e8f0;
}
.nav-btn {
background: #42b883;
color: white;
border: none;
padding: 10px 25px;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
font-weight: 500;
min-width: 100px;
}
.nav-btn:hover {
background: #368e6c;
}
.nav-btn:disabled {
background: #cbd5e0;
cursor: not-allowed;
}
.slide-counter {
text-align: center;
color: #718096;
font-size: 0.9rem;
margin-bottom: 10px;
font-weight: 500;
}
.terminal {
background: #2d3748;
color: #48bb78;
padding: 15px;
border-radius: 6px;
font-family: 'Consolas', monospace;
margin: 10px 0;
font-size: 0.9rem;
line-height: 1.5;
white-space: pre-wrap;
}
.api-example {
background: #fffaf0;
border: 1px solid #ed8936;
padding: 15px;
border-radius: 6px;
margin: 10px 0;
font-family: 'Consolas', monospace;
font-size: 0.9rem;
color: #c05621;
line-height: 1.5;
white-space: pre-wrap;
}
ul {
margin: 15px 0 15px 20px;
color: #4a5568;
}
li {
margin: 8px 0;
}
code {
background: #edf2f7;
padding: 2px 6px;
border-radius: 3px;
font-family: 'Consolas', monospace;
font-size: 0.9rem;
}
.comparison-table {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
font-size: 0.9rem;
}
.comparison-table th {
background: #42b883;
color: white;
padding: 10px;
text-align: left;
border: 1px solid #368e6c;
}
.comparison-table td {
padding: 10px;
border: 1px solid #e2e8f0;
}
.comparison-table tr:nth-child(even) {
background: #f7fafc;
}
.visual {
display: flex;
align-items: center;
justify-content: center;
margin: 20px 0;
padding: 20px;
background: #f8fafc;
border-radius: 8px;
}
.visual-item {
text-align: center;
margin: 0 20px;
}
.visual-icon {
font-size: 3rem;
margin-bottom: 10px;
}
.arrow {
font-size: 2rem;
color: #718096;
}
@media (max-width: 768px) {
body {
padding: 10px;
}
.slide {
padding: 20px;
}
h1 {
font-size: 1.8rem;
}
h2 {
font-size: 1.5rem;
}
h3 {
font-size: 1.2rem;
}
.visual {
flex-direction: column;
}
.arrow {
transform: rotate(90deg);
margin: 10px 0;
}
}
</style>
</head>
<body>
<div class="slide-counter" id="slide-counter">Slide 1 of 10</div>
<div class="container">
<!-- Slide 1: Title -->
<div class="slide active" id="slide1">
<div style="flex: 1; display: flex; flex-direction: column; justify-content: center;">
<h1>🌐 Building a Social Media Feed</h1>
<p style="font-size: 1.3rem; color: #4a5568;">Learn Vue.js, APIs, and Modern Web Development</p>
<p style="margin-top: 30px; font-size: 1.1rem; color: #718096;">
Create an interactive social media feed that connects to a real API
</p>
<div style="margin-top: 40px; background: #e6fffa; padding: 20px; border-radius: 8px;">
<h3 style="color: #0d9488;">What You'll Learn:</h3>
<ul>
<li>Why JavaScript frameworks make coding easier</li>
<li>What APIs are and how they work</li>
<li>How to install Node.js and create Vue apps</li>
<li>How to fetch data from an API with async/await</li>
<li>Build a working social media feed!</li>
</ul>
</div>
</div>
<div class="nav-container">
<button class="nav-btn" id="prevBtn1" disabled="">Previous</button>
<button class="nav-btn" id="nextBtn1">Next</button>
</div>
</div>
<!-- Slide 2: Why Frameworks? -->
<div class="slide" id="slide2">
<h2>🚀 Why JavaScript Frameworks?</h2>
<div class="analogy-block">
<h3>Think of Frameworks Like LEGO Kits!</h3>
<p><strong>Without a framework:</strong> You get a huge box of individual LEGO bricks. You have to figure everything out yourself!</p>
<p><strong>With a framework:</strong> You get a LEGO kit with pre-built sections and instructions. Just snap things together!</p>
</div>
<div class="visual">
<div class="visual-item">
<div class="visual-icon">🧱</div>
<h4>Old Way (Vanilla JS)</h4>
<p>Everything by hand</p>
<p>Slow and messy</p>
</div>
<div class="arrow"></div>
<div class="visual-item">
<div class="visual-icon">🏗️</div>
<h4>New Way (Frameworks)</h4>
<p>Pre-built components</p>
<p>Fast and organized</p>
</div>
</div>
<div class="instruction-block">
<h3>Framework Benefits:</h3>
<ul>
<li><strong>Save time:</strong> Don't reinvent the wheel</li>
<li><strong>Stay organized:</strong> Everything has its place</li>
<li><strong>Easy updates:</strong> Change one part, everything updates automatically</li>
<li><strong>Big community:</strong> Millions of developers to help you</li>
<li><strong>Best practices:</strong> Learn the right way from the start</li>
</ul>
</div>
<div class="nav-container">
<button class="nav-btn" id="prevBtn2" disabled="">Previous</button>
<button class="nav-btn" id="nextBtn3">Next</button>
</div>
</div>
<!-- Slide 3: Which Framework? -->
<div class="slide" id="slide3">
<h2>🟢 Why Vue.js is Our Choice</h2>
<table class="comparison-table">
<thead>
<tr>
<th>Framework</th>
<th>Who Makes It</th>
<th>Learning Curve</th>
<th>For Russian Users</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>React.js</strong></td>
<td>Facebook/Meta (USA)</td>
<td>Medium</td>
<td>⚠️ Risk of sanctions/blocking</td>
</tr>
<tr>
<td><strong>Angular</strong></td>
<td>Google (USA)</td>
<td>Steep</td>
<td>⚠️ Risk of sanctions/blocking</td>
</tr>
<tr>
<td><strong>Vue.js</strong> 🎯</td>
<td>Open Source Community 🌍</td>
<td>Gentle</td>
<td>✅ Safe &amp; Independent</td>
</tr>
</tbody>
</table>
<div class="instruction-block">
<h3>Vue.js Advantages:</h3>
<ul>
<li><strong>Open source:</strong> Belongs to everyone, not one company</li>
<li><strong>Gentle learning curve:</strong> Easy for beginners</li>
<li><strong>Great documentation:</strong> Like having a helpful teacher</li>
<li><strong>Single-file components:</strong> HTML + CSS + JavaScript together</li>
<li><strong>Reactive:</strong> Automatic updates (magic!)</li>
</ul>
</div>
<div class="analogy-block">
<h3>Choosing Vue is Like Choosing:</h3>
<p><strong>React/Angular:</strong> Renting a house - the owner (Meta/Google) can change rules or kick you out</p>
<p><strong>Vue.js:</strong> Owning a house - it's yours forever, no one can take it away!</p>
</div>
<div class="nav-container">
<button class="nav-btn" id="prevBtn3" disabled="">Previous</button>
<button class="nav-btn" id="nextBtn4">Next</button>
</div>
</div>
<!-- Slide 4: What is an API? -->
<div class="slide" id="slide4">
<h2>🤝 What is an API?</h2>
<div class="analogy-block">
<h3>API = Restaurant Waiter</h3>
<p>Think of an API like a waiter in a restaurant:</p>
<ul>
<li><strong>You (Browser):</strong> "I'd like posts from user 1" (places order)</li>
<li><strong>API (Waiter):</strong> Takes your order to the kitchen</li>
<li><strong>Database (Kitchen):</strong> Prepares the data</li>
<li><strong>API (Waiter):</strong> Brings the data back to you</li>
</ul>
</div>
<div class="visual">
<div class="visual-item">
<div class="visual-icon">🌐</div>
<h4>Your Vue App</h4>
<p>"Give me posts!"</p>
</div>
<div class="arrow"></div>
<div class="visual-item">
<div class="visual-icon">🤝</div>
<h4>API</h4>
<p>Messenger</p>
</div>
<div class="arrow"></div>
<div class="visual-item">
<div class="visual-icon">💾</div>
<h4>Database</h4>
<p>Data storage</p>
</div>
</div>
<div class="instruction-block">
<h3>Our API: api.techshare.cc</h3>
<p>We have a real API that serves data! Try these in your browser:</p>
<div class="api-example">
# See all posts:
https://api.techshare.cc/api/posts
# See all users:
https://api.techshare.cc/api/users
# See comments:
https://api.techshare.cc/api/comments
</div>
<p>Copy and paste these URLs in your browser to see the data!</p>
</div>
<div class="nav-container">
<button class="nav-btn" id="prevBtn4" disabled="">Previous</button>
<button class="nav-btn" id="nextBtn5">Next</button>
</div>
</div>
<!-- Slide 5: Install Node.js -->
<div class="slide" id="slide5">
<h2>📦 Step 1: Install Node.js</h2>
<div class="instruction-block">
<div class="step-number">1</div>
<strong>What is Node.js?</strong>
<p>Think of Node.js as the <strong>engine</strong> that runs JavaScript on your computer!</p>
<p>Usually JavaScript only runs in browsers. Node.js lets it run on YOUR computer too!</p>
</div>
<div class="instruction-block">
<div class="step-number">2</div>
<strong>Download and Install</strong>
<ul>
<li>Go to <a href="https://nodejs.org/" target="_blank">nodejs.org</a></li>
<li>Download the <strong>LTS version</strong> (Long Term Support = stable)</li>
<li>Run the installer</li>
<li>Click "Next" through everything</li>
</ul>
</div>
<div class="instruction-block">
<div class="step-number">3</div>
<strong>Check if it Works</strong>
<p>Open PowerShell (Windows) or Terminal (Mac):</p>
<div class="terminal">
# Check Node.js version
node --version
# Should show: v20.x.x or v22.x.x
# Check npm version
npm --version
# Should show: 10.x.x or higher
</div>
</div>
<div class="instruction-block">
<div class="step-number">4</div>
<strong>Windows Users - Fix Execution Policy</strong>
<p>If PowerShell says "not allowed":</p>
<div class="terminal">
# Open PowerShell as Administrator
# Type this:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
</div>
<p>Type <code>Y</code> and press Enter when asked!</p>
</div>
<div class="nav-container">
<button class="nav-btn" id="prevBtn5" disabled="">Previous</button>
<button class="nav-btn" id="nextBtn6">Next</button>
</div>
</div>
<!-- Slide 6: Create Vue App -->
<div class="slide" id="slide6">
<h2>⚡ Step 2: Create Vue App with Vite</h2>
<div class="instruction-block">
<div class="step-number">1</div>
<strong>Open Terminal/PowerShell</strong>
<p>Navigate to where you want your project:</p>
<div class="terminal">
cd Documents
# or wherever you want your project
</div>
</div>
<div class="instruction-block">
<div class="step-number">2</div>
<strong>Create Vue App</strong>
<p>Type this command (with double dash --):</p>
<div class="terminal">
# Create Vue app with Vite
npm create vite@latest my-vue-app -- --template vue
</div>
<p><strong>Note:</strong> <code>-- --template vue</code> means two dashes, space, two dashes</p>
</div>
<div class="instruction-block">
<div class="step-number">3</div>
<strong>Answer Prompts</strong>
<p>You'll see questions - just press Enter for all:</p>
<div class="terminal">
✔ Project name: … my-vue-app
✔ Package name: … my-vue-app
✔ Add TypeScript? … No
✔ Add JSX Support? … No
✔ Add Vue Router? … No (or Yes if you want pages)
✔ Add Pinia? … No (or Yes for state management)
✔ Add Vitest? … No
✔ Add ESLint? … No (or Yes for code quality)
</div>
</div>
<div class="instruction-block">
<div class="step-number">4</div>
<strong>Navigate to your app</strong>
<div class="terminal">
cd my-vue-app
</div>
</div>
<div class="nav-container">
<button class="nav-btn" id="prevBtn6" disabled="">Previous</button>
<button class="nav-btn" id="nextBtn7">Next</button>
</div>
</div>
<!-- Slide 7: Install and Run -->
<div class="slide" id="slide7">
<h2>🚀 Step 3: Install and Run</h2>
<div class="instruction-block">
<div class="step-number">1</div>
<strong>Install Dependencies</strong>
<p>These are like "batteries" for your app:</p>
<div class="terminal">
npm install
</div>
<p>Wait 1-2 minutes while it downloads everything</p>
</div>
<div class="instruction-block">
<div class="step-number">2</div>
<strong>Start Development Server</strong>
<div class="terminal">
npm run dev
</div>
<p>You'll see:</p>
<div class="terminal">
VITE v5.x.x ready in xxx ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
</div>
</div>
<div class="instruction-block">
<div class="step-number">3</div>
<strong>Open in Browser</strong>
<p>Copy and paste this in your browser:</p>
<div class="code-block">
http://localhost:5173
</div>
</div>
<div class="instruction-block">
<div class="step-number">4</div>
<strong>Explore the Default App</strong>
<ul>
<li>Click the count button - see it update!</li>
<li>Notice the Vue and Vite logos</li>
<li>This is your starting point</li>
</ul>
</div>
<div class="nav-container">
<button class="nav-btn" id="prevBtn7" disabled="">Previous</button>
<button class="nav-btn" id="nextBtn8">Next</button>
</div>
</div>
<!-- Slide 8: Project Structure -->
<div class="slide" id="slide8">
<h2>🗂️ Step 4: Understand Project Structure</h2>
<div class="instruction-block">
<p><strong>Your project folder looks like this:</strong></p>
<div class="code-block">
my-vue-app/ # Your project house
├── node_modules/ # Toolbox (don't touch!)
├── public/ # Front yard
│ └── vite.svg # Vite logo
├── src/ # Main house
│ ├── assets/ # Pictures &amp; decorations
│ │ └── vue.svg # Vue logo
│ ├── components/ # Furniture
│ │ └── HelloWorld.vue # Example furniture
│ ├── App.vue # Living room (main area)
│ └── main.js # Front door (starts app)
├── index.html # Land plot
├── package.json # Shopping list
└── vite.config.js # House blueprints
</div>
</div>
<div class="instruction-block">
<h3>Important Files:</h3>
<ul>
<li><strong>src/App.vue:</strong> Main component - we'll replace this</li>
<li><strong>src/main.js:</strong> Starts the Vue app</li>
<li><strong>index.html:</strong> Main HTML file</li>
<li><strong>package.json:</strong> Lists all tools we use</li>
</ul>
</div>
<div class="instruction-block">
<h3>Stop and Restart Server:</h3>
<p>In your terminal where <code>npm run dev</code> is running:</p>
<div class="terminal">
# Press Ctrl + C to stop
# Then restart:
npm run dev
</div>
</div>
<div class="nav-container">
<button class="nav-btn" id="prevBtn8" disabled="">Previous</button>
<button class="nav-btn" id="nextBtn9">Next</button>
</div>
</div>
<!-- Slide 9: Replace App.vue -->
<div class="slide" id="slide9">
<h2>🎨 Step 5: Create Social Media Feed</h2>
<div class="instruction-block">
<div class="step-number">1</div>
<strong>Open App.vue</strong>
<p>Navigate to: <code>my-vue-app/src/App.vue</code></p>
<p>Open it in your code editor (VS Code, Notepad++, etc.)</p>
</div>
<div class="instruction-block">
<div class="step-number">2</div>
<strong>Delete Everything</strong>
<p>Select all code in App.vue and delete it</p>
</div>
<div class="instruction-block">
<div class="step-number">3</div>
<strong>Paste Our Social Feed Code</strong>
<p>Copy and paste this complete code:</p>
</div>
<div class="code-block" style="max-height: 400px; overflow-y: auto; font-size: 0.8rem;">
&lt;template&gt;
&lt;div class="social-feed"&gt;
&lt;!-- Header --&gt;
&lt;header class="header"&gt;
&lt;h1&gt;📱 Social Media Feed&lt;/h1&gt;
&lt;p class="subtitle"&gt;Simple feed using Async/Await&lt;/p&gt;
&lt;/header&gt;
&lt;!-- Main Feed --&gt;
&lt;main class="feed"&gt;
&lt;!-- Stats --&gt;
&lt;div class="stats"&gt;
&lt;p&gt;Total posts: {{ posts.length }}&lt;/p&gt;
&lt;button @click="loadPosts" :disabled="loading" class="refresh-btn"&gt;
{{ loading ? '🔄 Loading...' : '🔄 Refresh' }}
&lt;/button&gt;
&lt;/div&gt;
&lt;!-- Loading --&gt;
&lt;div v-if="loading" class="loading"&gt;
&lt;div class="spinner"&gt;&lt;/div&gt;
&lt;p&gt;Loading posts...&lt;/p&gt;
&lt;/div&gt;
&lt;!-- Error --&gt;
&lt;div v-else-if="error" class="error"&gt;
&lt;p&gt;❌ Error: {{ error }}&lt;/p&gt;
&lt;button @click="loadPosts" class="retry-btn"&gt;Try Again&lt;/button&gt;
&lt;/div&gt;
&lt;!-- Posts --&gt;
&lt;div v-else class="posts"&gt;
&lt;div v-if="posts.length === 0" class="empty"&gt;
&lt;p&gt;No posts available.&lt;/p&gt;
&lt;/div&gt;
&lt;div v-else class="posts-list"&gt;
&lt;div
v-for="post in posts"
:key="post._id || post.id"
class="post"
&gt;
&lt;!-- User info --&gt;
&lt;div class="user-info"&gt;
&lt;div class="avatar"&gt;U{{ post.userId }}&lt;/div&gt;
&lt;div&gt;
&lt;h3&gt;User {{ post.userId }}&lt;/h3&gt;
&lt;small&gt;Post ID: {{ (post._id || post.id).substring(0, 10) }}...&lt;/small&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- Post content --&gt;
&lt;div class="post-content"&gt;
&lt;h4&gt;{{ post.title }}&lt;/h4&gt;
&lt;p&gt;{{ post.body || post.content }}&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/main&gt;
&lt;!-- Footer --&gt;
&lt;footer class="footer"&gt;
&lt;p&gt;API: https://api.techshare.cc/api/posts&lt;/p&gt;
&lt;/footer&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;script setup&gt;
import { ref, onMounted } from 'vue'
// State
const posts = ref([])
const loading = ref(false)
const error = ref(null)
// Load posts function
async function loadPosts() {
loading.value = true
error.value = null
try {
console.log('Fetching posts...')
const response = await fetch('https://api.techshare.cc/api/posts')
if (!response.ok) {
throw new Error(`Failed to fetch: ${response.status}`)
}
posts.value = await response.json()
console.log(`Loaded ${posts.value.length} posts`)
} catch (err) {
console.error('Error:', err)
error.value = err.message || 'Something went wrong'
} finally {
loading.value = false
}
}
// Load on page load
onMounted(() =&gt; {
loadPosts()
})
&lt;/script&gt;
&lt;style scoped&gt;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.social-feed {
min-height: 100vh;
background: #f5f7fa;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
/* Header */
.header {
background: white;
padding: 2rem;
text-align: center;
border-bottom: 1px solid #eaeaea;
}
.header h1 {
color: #333;
font-size: 2rem;
margin-bottom: 0.5rem;
}
.subtitle {
color: #666;
font-size: 1rem;
}
/* Feed */
.feed {
max-width: 800px;
margin: 0 auto;
padding: 2rem;
}
/* Stats */
.stats {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
padding: 1rem;
background: white;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.stats p {
font-weight: 600;
color: #333;
}
.refresh-btn {
padding: 0.5rem 1rem;
background: #4361ee;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: 500;
}
.refresh-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Loading */
.loading {
text-align: center;
padding: 3rem;
}
.spinner {
width: 40px;
height: 40px;
border: 3px solid #ddd;
border-top: 3px solid #4361ee;
border-radius: 50%;
margin: 0 auto 1rem;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Error */
.error {
text-align: center;
padding: 2rem;
background: #ffebee;
color: #c62828;
border-radius: 8px;
margin-bottom: 1rem;
}
.retry-btn {
margin-top: 1rem;
padding: 0.5rem 1.5rem;
background: #c62828;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
/* Empty */
.empty {
text-align: center;
padding: 3rem;
color: #666;
}
/* Posts list */
.posts-list {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
/* Single post */
.post {
background: white;
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
/* User info */
.user-info {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 1px solid #f0f0f0;
}
.avatar {
width: 50px;
height: 50px;
background: #4361ee;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 1.2rem;
}
.user-info h3 {
color: #333;
margin-bottom: 0.25rem;
}
.user-info small {
color: #888;
font-size: 0.85rem;
}
/* Post content */
.post-content h4 {
color: #333;
margin-bottom: 0.75rem;
font-size: 1.1rem;
line-height: 1.4;
}
.post-content p {
color: #555;
line-height: 1.6;
font-size: 0.95rem;
}
/* Footer */
.footer {
text-align: center;
padding: 2rem;
color: #666;
font-size: 0.9rem;
border-top: 1px solid #eaeaea;
margin-top: 3rem;
}
/* Responsive */
@media (max-width: 768px) {
.header {
padding: 1.5rem;
}
.header h1 {
font-size: 1.5rem;
}
.feed {
padding: 1rem;
}
.stats {
flex-direction: column;
gap: 1rem;
text-align: center;
}
.post {
padding: 1rem;
}
.user-info {
gap: 0.75rem;
}
.avatar {
width: 40px;
height: 40px;
font-size: 1rem;
}
}
&lt;/style&gt;
</div>
<div class="nav-container">
<button class="nav-btn" id="prevBtn9" disabled="">Previous</button>
<button class="nav-btn" id="nextBtn10">Next</button>
</div>
</div>
<!-- Slide 10: See the Magic! -->
<div class="slide" id="slide10">
<h2>🎉 Step 6: See the Magic Happen!</h2>
<div class="instruction-block">
<div class="step-number">1</div>
<strong>Save App.vue</strong>
<p>Save the file (Ctrl + S or Cmd + S)</p>
</div>
<div class="instruction-block">
<div class="step-number">2</div>
<strong>Check Your Browser</strong>
<p>Go to <code>http://localhost:5173</code></p>
<p>You should see:</p>
<ul>
<li>A beautiful social media feed header</li>
<li>Posts loading from the API</li>
<li>Real data from api.techshare.cc</li>
<li>A refresh button to get new data</li>
</ul>
</div>
<div class="instruction-block">
<h3>What Just Happened? Magic!</h3>
<div class="visual">
<div class="visual-item">
<div class="visual-icon">🌐</div>
<h4>Your Vue App</h4>
<p>Said "give me posts"</p>
</div>
<div class="arrow"></div>
<div class="visual-item">
<div class="visual-icon">🤝</div>
<h4>API</h4>
<p>Messenger delivered</p>
</div>
<div class="arrow"></div>
<div class="visual-item">
<div class="visual-icon">💾</div>
<h4>Database</h4>
<p>Gave real data</p>
</div>
</div>
</div>
<div class="analogy-block">
<h3>Async/Await = Super Fast Messenger</h3>
<p><strong>async function loadPosts():</strong> "I'll do this job, but I might need to wait"</p>
<p><strong>await fetch():</strong> "Wait here until you get the data"</p>
<p><strong>.then() vs async/await:</strong> Phone call vs text message!</p>
</div>
<div class="instruction-block" style="background: #e6fffa; border-left: 4px solid #0d9488;">
<h3>🎓 What You've Accomplished:</h3>
<ul>
<li>✅ Learned why frameworks save time</li>
<li>✅ Chose Vue.js (safe open source option)</li>
<li>✅ Installed Node.js and npm</li>
<li>✅ Created a Vue app with Vite</li>
<li>✅ Connected to a real API</li>
<li>✅ Built a working social media feed!</li>
</ul>
</div>
<div class="nav-container">
<button class="nav-btn" id="prevBtn10" disabled="">Previous</button>
<button class="nav-btn" id="nextBtn11">Finish</button>
</div>
</div>
</div>
<script>
const totalSlides = 10;
let currentSlide = 1;
function updateSlideCounter() {
document.getElementById('slide-counter').textContent = `Slide ${currentSlide} of ${totalSlides}`;
}
function showSlide(slideNumber) {
for (let i = 1; i <= totalSlides; i++) {
const slide = document.getElementById(`slide${i}`);
if (slide) slide.classList.remove('active');
}
const slideElement = document.getElementById(`slide${slideNumber}`);
if (slideElement) {
slideElement.classList.add('active');
currentSlide = slideNumber;
updateSlideCounter();
updateButtons();
}
}
function updateButtons() {
for (let i = 1; i <= totalSlides; i++) {
const prevBtn = document.getElementById(`prevBtn${i}`);
const nextBtn = document.getElementById(`nextBtn${i}`);
if (prevBtn) prevBtn.disabled = currentSlide === 1;
if (nextBtn) {
nextBtn.textContent = currentSlide === totalSlides ? 'Finish' : 'Next';
}
}
}
for (let i = 1; i <= totalSlides; i++) {
const nextBtn = document.getElementById(`nextBtn${i}`);
const prevBtn = document.getElementById(`prevBtn${i}`);
if (nextBtn) {
nextBtn.addEventListener('click', () => {
if (currentSlide < totalSlides) {
showSlide(currentSlide + 1);
} else {
alert('🎉 Congratulations! You now understand Vue.js, APIs, and async/await! You\'ve built a real social media feed that connects to live data. Keep exploring and building!');
}
});
}
if (prevBtn) {
prevBtn.addEventListener('click', () => {
if (currentSlide > 1) {
showSlide(currentSlide - 1);
}
});
}
}
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowRight' || e.key === ' ') {
if (currentSlide < totalSlides) showSlide(currentSlide + 1);
} else if (e.key === 'ArrowLeft') {
if (currentSlide > 1) showSlide(currentSlide - 1);
}
});
updateSlideCounter();
updateButtons();
</script>
</body></html>