anthem-space / index.html
Anthem7b4k's picture
Add 3 files
2b4cb0f verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VIGO - Connect with Friends</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.chat-bubble {
max-width: 70%;
border-radius: 1rem;
padding: 0.75rem;
margin-bottom: 0.5rem;
}
.sender {
background-color: #dcf8c6;
align-self: flex-end;
}
.receiver {
background-color: #ffffff;
align-self: flex-start;
}
.status-viewer {
height: 400px;
background-size: cover;
background-position: center;
}
.gradient-bg {
background: linear-gradient(135deg, #25d366 0%, #128c7e 100%);
}
.slide-enter-active, .slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter-from, .slide-leave-to {
transform: translateX(100%);
opacity: 0;
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
</style>
</head>
<body class="bg-gray-100 font-sans">
<div id="app" class="min-h-screen">
<!-- Auth Screen -->
<div v-if="!isAuthenticated" class="flex items-center justify-center min-h-screen gradient-bg">
<div class="bg-white p-8 rounded-lg shadow-lg w-full max-w-md mx-4">
<div class="text-center mb-8">
<img src="https://via.placeholder.com/80" alt="VIGO Logo" class="mx-auto mb-4 rounded-full">
<h1 class="text-3xl font-bold text-gray-800">VIGO</h1>
<p class="text-gray-600">Connect with friends and family</p>
</div>
<div v-if="authMode === 'login'" class="space-y-4">
<div>
<label class="block text-gray-700 mb-2">Phone or Email</label>
<input v-model="loginIdentifier" type="text" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500">
</div>
<div>
<label class="block text-gray-700 mb-2">Password</label>
<input v-model="loginPassword" type="password" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500">
</div>
<button @click="login" class="w-full bg-green-500 text-white py-2 rounded-lg hover:bg-green-600 transition duration-200">
Log In
</button>
<p class="text-center text-gray-600 mt-4">
Don't have an account?
<a @click="authMode = 'signup'" class="text-green-500 cursor-pointer hover:underline">Sign up</a>
</p>
</div>
<div v-if="authMode === 'signup'" class="space-y-4">
<div>
<label class="block text-gray-700 mb-2">Full Name</label>
<input v-model="signupName" type="text" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500">
</div>
<div>
<label class="block text-gray-700 mb-2">Phone or Email</label>
<input v-model="signupIdentifier" type="text" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500">
</div>
<div>
<label class="block text-gray-700 mb-2">Password</label>
<input v-model="signupPassword" type="password" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500">
</div>
<button @click="signup" class="w-full bg-green-500 text-white py-2 rounded-lg hover:bg-green-600 transition duration-200">
Sign Up
</button>
<p class="text-center text-gray-600 mt-4">
Already have an account?
<a @click="authMode = 'login'" class="text-green-500 cursor-pointer hover:underline">Log in</a>
</p>
</div>
</div>
</div>
<!-- Main App -->
<div v-if="isAuthenticated" class="flex h-screen">
<!-- Sidebar -->
<div class="w-1/4 border-r bg-white flex flex-col">
<!-- Header -->
<div class="p-3 bg-gray-100 flex justify-between items-center">
<div class="flex items-center">
<img :src="currentUser.avatar" alt="Profile" class="w-10 h-10 rounded-full mr-2">
<span class="font-semibold">{{ currentUser.name }}</span>
</div>
<div class="flex space-x-4 text-gray-600">
<i class="fas fa-search cursor-pointer"></i>
<i class="fas fa-ellipsis-v cursor-pointer"></i>
</div>
</div>
<!-- Tabs -->
<div class="flex border-b">
<button @click="activeTab = 'chats'" :class="{'text-green-500 border-b-2 border-green-500': activeTab === 'chats'}" class="flex-1 py-3 font-medium">
Chats
</button>
<button @click="activeTab = 'status'" :class="{'text-green-500 border-b-2 border-green-500': activeTab === 'status'}" class="flex-1 py-3 font-medium">
Status
</button>
<button @click="activeTab = 'news'" :class="{'text-green-500 border-b-2 border-green-500': activeTab === 'news'}" class="flex-1 py-3 font-medium">
News
</button>
</div>
<!-- Chats List -->
<div v-if="activeTab === 'chats'" class="flex-1 overflow-y-auto">
<div v-for="chat in chats" :key="chat.id" @click="openChat(chat)" class="p-3 border-b flex items-center hover:bg-gray-100 cursor-pointer">
<img :src="chat.avatar" alt="Profile" class="w-12 h-12 rounded-full mr-3">
<div class="flex-1">
<div class="flex justify-between">
<span class="font-semibold">{{ chat.name }}</span>
<span class="text-xs text-gray-500">{{ chat.lastMessageTime }}</span>
</div>
<p class="text-sm text-gray-600 truncate">{{ chat.lastMessage }}</p>
</div>
</div>
</div>
<!-- Status List -->
<div v-if="activeTab === 'status'" class="flex-1 overflow-y-auto">
<div class="p-3 border-b">
<div class="flex items-center mb-3">
<div class="relative">
<img :src="currentUser.avatar" alt="Profile" class="w-12 h-12 rounded-full mr-3">
<div class="absolute bottom-0 right-2 bg-green-500 rounded-full w-4 h-4 flex items-center justify-center">
<i class="fas fa-plus text-white text-xs"></i>
</div>
</div>
<div>
<p class="font-semibold">My Status</p>
<p class="text-sm text-gray-600">Tap to add status update</p>
</div>
</div>
</div>
<div class="p-3">
<p class="text-gray-500 uppercase text-xs mb-2">Recent updates</p>
<div v-for="status in statusUpdates" :key="status.id" @click="viewStatus(status)" class="flex items-center mb-3 hover:bg-gray-100 p-2 rounded cursor-pointer">
<div class="relative">
<img :src="status.user.avatar" alt="Profile" class="w-12 h-12 rounded-full mr-3 border-2 border-green-500">
</div>
<div>
<p class="font-semibold">{{ status.user.name }}</p>
<p class="text-sm text-gray-600">{{ status.time }}</p>
</div>
</div>
</div>
</div>
<!-- News Feed -->
<div v-if="activeTab === 'news'" class="flex-1 overflow-y-auto p-3">
<div class="mb-4">
<div class="flex items-center mb-3">
<img :src="currentUser.avatar" alt="Profile" class="w-10 h-10 rounded-full mr-2">
<input type="text" placeholder="What's on your mind?" class="flex-1 bg-gray-100 rounded-full py-2 px-4 focus:outline-none">
</div>
<div class="flex justify-between border-t pt-2">
<button class="flex items-center text-gray-600 hover:bg-gray-100 px-2 py-1 rounded">
<i class="fas fa-image text-green-500 mr-1"></i>
<span>Photo</span>
</button>
<button class="flex items-center text-gray-600 hover:bg-gray-100 px-2 py-1 rounded">
<i class="fas fa-user-tag text-blue-500 mr-1"></i>
<span>Tag</span>
</button>
<button class="flex items-center text-gray-600 hover:bg-gray-100 px-2 py-1 rounded">
<i class="fas fa-map-marker-alt text-red-500 mr-1"></i>
<span>Location</span>
</button>
</div>
</div>
<div v-for="post in newsFeed" :key="post.id" class="bg-white rounded-lg shadow mb-4">
<div class="p-3">
<div class="flex items-center mb-2">
<img :src="post.user.avatar" alt="Profile" class="w-8 h-8 rounded-full mr-2">
<div>
<p class="font-semibold text-sm">{{ post.user.name }}</p>
<p class="text-xs text-gray-500">{{ post.time }}</p>
</div>
</div>
<p class="mb-2">{{ post.content }}</p>
<img v-if="post.image" :src="post.image" alt="Post" class="w-full rounded mb-2">
<div class="flex justify-between text-gray-500 text-sm border-t pt-2">
<button class="flex items-center hover:text-green-500">
<i class="far fa-thumbs-up mr-1"></i>
<span>{{ post.likes }}</span>
</button>
<button class="hover:text-green-500">
<span>{{ post.comments }} comments</span>
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Chat Area -->
<div v-if="activeChat" class="flex-1 flex flex-col bg-gray-50">
<!-- Chat Header -->
<div class="p-3 bg-gray-100 flex justify-between items-center border-b">
<div class="flex items-center">
<img :src="activeChat.avatar" alt="Profile" class="w-10 h-10 rounded-full mr-3">
<div>
<p class="font-semibold">{{ activeChat.name }}</p>
<p class="text-xs text-gray-600">Online</p>
</div>
</div>
<div class="flex space-x-4 text-gray-600">
<i class="fas fa-search cursor-pointer"></i>
<i class="fas fa-phone-alt cursor-pointer"></i>
<i class="fas fa-video cursor-pointer"></i>
<i class="fas fa-ellipsis-v cursor-pointer"></i>
</div>
</div>
<!-- Messages -->
<div class="flex-1 overflow-y-auto p-4 space-y-2 flex flex-col">
<div v-for="message in activeChat.messages" :key="message.id" :class="{'sender': message.sender === 'me', 'receiver': message.sender !== 'me'}" class="chat-bubble">
<p>{{ message.text }}</p>
<p class="text-xs text-gray-500 text-right mt-1">{{ message.time }}</p>
</div>
</div>
<!-- Message Input -->
<div class="p-3 bg-white border-t flex items-center">
<i class="fas fa-smile text-gray-500 text-xl mx-2 cursor-pointer"></i>
<i class="fas fa-paperclip text-gray-500 text-xl mx-2 cursor-pointer"></i>
<input v-model="newMessage" @keyup.enter="sendMessage" type="text" placeholder="Type a message" class="flex-1 border rounded-full py-2 px-4 focus:outline-none">
<button @click="sendMessage" class="ml-2 bg-green-500 text-white rounded-full w-10 h-10 flex items-center justify-center">
<i class="fas fa-paper-plane"></i>
</button>
</div>
</div>
<!-- Status Viewer -->
<div v-if="viewingStatus" class="fixed inset-0 bg-black z-50 flex items-center justify-center">
<div class="status-viewer w-full max-w-md" :style="{'background-image': 'url(' + viewingStatus.image + ')'}">
<div class="bg-gradient-to-t from-black to-transparent h-full flex flex-col justify-between p-4">
<div class="flex justify-between items-center">
<button @click="viewingStatus = null" class="text-white">
<i class="fas fa-times"></i>
</button>
<div class="flex items-center">
<img :src="viewingStatus.user.avatar" alt="Profile" class="w-8 h-8 rounded-full mr-2">
<div>
<p class="text-white font-semibold">{{ viewingStatus.user.name }}</p>
<p class="text-white text-xs">{{ viewingStatus.time }}</p>
</div>
</div>
</div>
<div class="flex justify-center mb-4">
<input type="text" placeholder="Send message" class="bg-black bg-opacity-50 text-white rounded-full py-2 px-4 w-full max-w-xs focus:outline-none">
</div>
</div>
</div>
</div>
<!-- No Chat Selected -->
<div v-if="!activeChat && activeTab !== 'news'" class="flex-1 flex flex-col items-center justify-center bg-gray-50">
<div class="text-center p-8">
<img src="https://via.placeholder.com/150" alt="VIGO" class="mx-auto mb-4">
<h2 class="text-2xl font-semibold text-gray-700 mb-2">VIGO Web</h2>
<p class="text-gray-600 mb-6">Send and receive messages without keeping your phone online.</p>
<p class="text-gray-500 text-sm">Select a chat to start messaging</p>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.47/dist/vue.global.min.js"></script>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const isAuthenticated = ref(false);
const authMode = ref('login');
const loginIdentifier = ref('');
const loginPassword = ref('');
const signupName = ref('');
const signupIdentifier = ref('');
const signupPassword = ref('');
const activeTab = ref('chats');
const activeChat = ref(null);
const newMessage = ref('');
const viewingStatus = ref(null);
const currentUser = ref({
id: 1,
name: 'John Doe',
avatar: 'https://randomuser.me/api/portraits/men/1.jpg',
phone: '+1234567890',
email: 'john@example.com'
});
const chats = ref([
{
id: 1,
name: 'Sarah Smith',
avatar: 'https://randomuser.me/api/portraits/women/1.jpg',
lastMessage: 'Hey, how are you doing?',
lastMessageTime: '10:30 AM',
messages: [
{ id: 1, text: 'Hey there!', sender: 'them', time: '10:20 AM' },
{ id: 2, text: 'How are you?', sender: 'them', time: '10:21 AM' },
{ id: 3, text: "I'm good, thanks! How about you?", sender: 'me', time: '10:25 AM' },
{ id: 4, text: 'Hey, how are you doing?', sender: 'them', time: '10:30 AM' }
]
},
{
id: 2,
name: 'Mike Johnson',
avatar: 'https://randomuser.me/api/portraits/men/2.jpg',
lastMessage: 'Meeting at 3 PM tomorrow',
lastMessageTime: 'Yesterday',
messages: [
{ id: 1, text: 'Hi Mike!', sender: 'me', time: '9:00 AM' },
{ id: 2, text: 'Hello! How are you?', sender: 'them', time: '9:05 AM' },
{ id: 3, text: 'Just wanted to confirm our meeting', sender: 'me', time: '9:10 AM' },
{ id: 4, text: 'Meeting at 3 PM tomorrow', sender: 'them', time: '9:15 AM' }
]
},
{
id: 3,
name: 'Emma Wilson',
avatar: 'https://randomuser.me/api/portraits/women/2.jpg',
lastMessage: 'The documents are ready',
lastMessageTime: 'Monday',
messages: [
{ id: 1, text: 'Hi Emma, are the documents ready?', sender: 'me', time: '2:00 PM' },
{ id: 2, text: 'Working on them now', sender: 'them', time: '2:30 PM' },
{ id: 3, text: 'Thanks!', sender: 'me', time: '2:35 PM' },
{ id: 4, text: 'The documents are ready', sender: 'them', time: '4:00 PM' }
]
}
]);
const statusUpdates = ref([
{
id: 1,
user: {
id: 2,
name: 'Sarah Smith',
avatar: 'https://randomuser.me/api/portraits/women/1.jpg'
},
image: 'https://picsum.photos/500/800?random=1',
time: '30 minutes ago'
},
{
id: 2,
user: {
id: 3,
name: 'Mike Johnson',
avatar: 'https://randomuser.me/api/portraits/men/2.jpg'
},
image: 'https://picsum.photos/500/800?random=2',
time: '1 hour ago'
},
{
id: 3,
user: {
id: 4,
name: 'Emma Wilson',
avatar: 'https://randomuser.me/api/portraits/women/2.jpg'
},
image: 'https://picsum.photos/500/800?random=3',
time: '2 hours ago'
}
]);
const newsFeed = ref([
{
id: 1,
user: {
id: 2,
name: 'Sarah Smith',
avatar: 'https://randomuser.me/api/portraits/women/1.jpg'
},
content: 'Just finished my morning hike! The view was amazing.',
image: 'https://picsum.photos/500/300?random=4',
time: '2 hours ago',
likes: 24,
comments: 5
},
{
id: 2,
user: {
id: 3,
name: 'Mike Johnson',
avatar: 'https://randomuser.me/api/portraits/men/2.jpg'
},
content: 'Working on a new project. Can\'t wait to share it with everyone!',
time: '5 hours ago',
likes: 12,
comments: 3
},
{
id: 3,
user: {
id: 4,
name: 'Emma Wilson',
avatar: 'https://randomuser.me/api/portraits/women/2.jpg'
},
content: 'Beautiful day at the beach with friends!',
image: 'https://picsum.photos/500/300?random=5',
time: '1 day ago',
likes: 42,
comments: 8
}
]);
const login = () => {
// Simple validation
if (!loginIdentifier.value || !loginPassword.value) {
alert('Please enter both phone/email and password');
return;
}
// In a real app, you would make an API call here
isAuthenticated.value = true;
};
const signup = () => {
// Simple validation
if (!signupName.value || !signupIdentifier.value || !signupPassword.value) {
alert('Please fill in all fields');
return;
}
// In a real app, you would make an API call here
isAuthenticated.value = true;
};
const openChat = (chat) => {
activeChat.value = chat;
};
const sendMessage = () => {
if (!newMessage.value.trim()) return;
const chat = activeChat.value;
const now = new Date();
const timeString = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
chat.messages.push({
id: chat.messages.length + 1,
text: newMessage.value,
sender: 'me',
time: timeString
});
chat.lastMessage = newMessage.value;
chat.lastMessageTime = timeString;
newMessage.value = '';
// Auto-scroll to bottom
setTimeout(() => {
const chatContainer = document.querySelector('.overflow-y-auto');
chatContainer.scrollTop = chatContainer.scrollHeight;
}, 10);
};
const viewStatus = (status) => {
viewingStatus.value = status;
};
return {
isAuthenticated,
authMode,
loginIdentifier,
loginPassword,
signupName,
signupIdentifier,
signupPassword,
activeTab,
activeChat,
newMessage,
viewingStatus,
currentUser,
chats,
statusUpdates,
newsFeed,
login,
signup,
openChat,
sendMessage,
viewStatus
};
}
}).mount('#app');
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Anthem7b4k/anthem-space" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>