This commit is contained in:
2026-01-20 17:54:05 +03:00
parent 065adb8494
commit 447578a218
19 changed files with 1185 additions and 5113 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1595
README.md

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

24
my-vue-app/.gitignore vendored
View File

@@ -1,24 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -1,3 +0,0 @@
{
"recommendations": ["Vue.volar"]
}

View File

@@ -1,5 +0,0 @@
# Vue 3 + Vite
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
Learn more about IDE Support for Vue in the [Vue Docs Scaling up Guide](https://vuejs.org/guide/scaling-up/tooling.html#ide-support).

View File

@@ -1,13 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>my-vue-app</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +0,0 @@
{
"name": "my-vue-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.5.24"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.1",
"vite": "^7.2.4"
}
}

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,332 +0,0 @@
<template>
<div class="social-feed">
<!-- Header -->
<header class="header">
<h1>📱 Social Media Feed</h1>
<p class="subtitle">Simple feed using Async/Await</p>
</header>
<!-- Main Feed -->
<main class="feed">
<!-- Stats -->
<div class="stats">
<p>Total posts: {{ posts.length }}</p>
<button @click="loadPosts" :disabled="loading" class="refresh-btn">
{{ loading ? '🔄 Loading...' : '🔄 Refresh' }}
</button>
</div>
<!-- Loading -->
<div v-if="loading" class="loading">
<div class="spinner"></div>
<p>Loading posts...</p>
</div>
<!-- Error -->
<div v-else-if="error" class="error">
<p> Error: {{ error }}</p>
<button @click="loadPosts" class="retry-btn">Try Again</button>
</div>
<!-- Posts -->
<div v-else class="posts">
<div v-if="posts.length === 0" class="empty">
<p>No posts available.</p>
</div>
<div v-else class="posts-list">
<div
v-for="post in posts"
:key="post._id || post.id"
class="post"
>
<!-- User info -->
<div class="user-info">
<div class="avatar">U{{ post.userId }}</div>
<div>
<h3>User {{ post.userId }}</h3>
<small>Post ID: {{ (post._id || post.id).substring(0, 10) }}...</small>
</div>
</div>
<!-- Post content -->
<div class="post-content">
<h4>{{ post.title }}</h4>
<p>{{ post.body || post.content }}</p>
</div>
</div>
</div>
</div>
</main>
<!-- Footer -->
<footer class="footer">
<p>API: https://api.techshare.cc/api/posts</p>
</footer>
</div>
</template>
<script setup>
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(() => {
loadPosts()
})
</script>
<style scoped>
* {
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;
}
}
</style>

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

Before

Width:  |  Height:  |  Size: 496 B

View File

@@ -1,43 +0,0 @@
<script setup>
import { ref } from 'vue'
defineProps({
msg: String,
})
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Learn more about IDE Support for Vue in the
<a
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
target="_blank"
>Vue Docs Scaling up Guide</a
>.
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>

View File

@@ -1,5 +0,0 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
createApp(App).mount('#app')

View File

@@ -1,79 +0,0 @@
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

View File

@@ -1,7 +0,0 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vite.dev/config/
export default defineConfig({
plugins: [vue()],
})

View File

@@ -1,300 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Maxy - Social Platform</title>
<!-- TAILWIND CSS CDN -->
<script src="/css/tailwind.css"></script>
</head>
<body>
<!-- Navigation Bar -->
<nav >
<div>
<div>
<a href="#">
<!-- Logo Image -->
<div>
M
</div>
<span>Maxy</span>
</a>
<!-- Mobile menu button -->
<a role="button" aria-label="menu" aria-expanded="false" data-target="navbarMenu">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarMenu">
<div>
<a>
<span>
<!-- Home icon would go here -->
</span>
<span>Home</span>
</a>
<a>
<span>
<!-- Hashtag icon would go here -->
</span>
<span>Explore</span>
</a>
<a>
<span>
<!-- Bell icon would go here -->
</span>
<span>Notifications</span>
</a>
<a>
<span>
<!-- Envelope icon would go here -->
</span>
<span>Messages</span>
</a>
<a>
<span>
<!-- User icon would go here -->
</span>
<span>Profile</span>
</a>
<a>
<span>
<!-- User icon would go here -->
</span>
<button>Message</button>
</a>
</div>
</div>
</div>
</nav>
<!-- Main Content -->
<section>
<div>
<div>
<!-- Left Sidebar -->
<div>
<!-- Profile Card -->
<div>
<div>
<div>
JS
</div>
<h2>John Smith</h2>
<p>@johnsmith</p>
<div>
<div>
<div>
<p>Posts</p>
<p>245</p>
</div>
</div>
<div>
<div>
<p>Followers</p>
<p>1.2K</p>
</div>
</div>
<div>
<div>
<p>Following</p>
<p>562</p>
</div>
</div>
</div>
</div>
</div>
<!-- Removed Trending Card -->
</div>
<!-- Main Feed -->
<div>
<!-- Create Post Card -->
<div>
<div>
<div>
<textarea placeholder="What's happening?"></textarea>
</div>
<div>
<div>
<button>
<span>
<!-- Image icon would go here -->
</span>
</button>
<button>
<span>
<!-- Smile icon would go here -->
</span>
</button>
<button>
<span>
<!-- Chart icon would go here -->
</span>
</button>
</div>
<button>
Send a Message
</button>
</div>
</div>
</div>
<div>
<article>
<div>
<div>
BM
</div>
</div>
<div>
<div>
<p>
<strong>Barbara Middleton</strong>
<br />
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis porta eros
lacus, nec ultricies elit blandit non. Suspendisse pellentesque mauris
sit amet dolor blandit rutrum. Nunc in tempus turpis.
<br />
<small><a>Like</a> · <a>Reply</a> · 3 hrs</small>
</p>
</div>
<article>
<div>
<div>
SB
</div>
</div>
<div>
<div>
<p>
<strong>Sean Brown</strong>
<br />
Donec sollicitudin urna eget eros malesuada sagittis. Pellentesque
habitant morbi tristique senectus et netus et malesuada fames ac
turpis egestas. Aliquam blandit nisl a nulla sagittis, a lobortis
leo feugiat.
<br />
<small><a>Like</a> · <a>Reply</a> · 2 hrs</small>
</p>
</div>
<article>
<div>
<div>
SJ
</div>
</div>
<div>
<div>
<p>
<strong>Sarah Johnson</strong>
<br />
Vivamus quis semper metus, non tincidunt dolor. Vivamus in mi eu lorem
cursus ullamcorper sit amet nec massa.
<br />
<small><a>Like</a> · <a>Reply</a> · 1 hr</small>
</p>
</div>
</div>
</article>
<article>
<div>
<div>
MC
</div>
</div>
<div>
<div>
<p>
<strong>Michael Chen</strong>
<br />
Morbi vitae diam et purus tincidunt porttitor vel vitae augue.
Praesent malesuada metus sed pharetra euismod. Cras tellus odio,
tincidunt iaculis diam non, porta aliquet tortor.
<br />
<small><a>Like</a> · <a>Reply</a> · 45 mins</small>
</p>
</div>
</div>
</article>
</div>
</article>
<article>
<div>
<div>
KE
</div>
</div>
<div>
<div>
<p>
<strong>Kayli Eunice</strong>
<br />
Sed convallis scelerisque mauris, non pulvinar nunc mattis vel.
Maecenas varius felis sit amet magna vestibulum euismod malesuada
cursus libero. Vestibulum ante ipsum primis in faucibus orci luctus
et ultrices posuere cubilia Curae; Phasellus lacinia non nisl id
feugiat.
<br />
<small><a>Like</a> · <a>Reply</a> · 2 hrs</small>
</p>
</div>
</div>
</article>
</div>
</article>
<article>
<div>
<div>
UU
</div>
</div>
<div>
<div>
<p class="control">
<textarea placeholder="Add a comment..."></textarea>
</p>
</div>
<div>
<p class="control">
<button>Post comment</button>
</p>
</div>
</div>
</article>
</div>
</div>
</div>
</div>
</section>
<!-- Scripts -->
<script>
// Mobile menu toggle
document.addEventListener('DOMContentLoaded', () => {
const navbarBurger = document.querySelector('.navbar-burger');
if(navbarBurger) {
navbarBurger.addEventListener('click', () => {
const target = navbarBurger.dataset.target;
const targetElement = document.getElementById(target);
navbarBurger.classList.toggle('is-active');
targetElement.classList.toggle('is-active');
});
}
});
</script>
</body>
</html>